You've already forked revanced-patcher
mirror of
https://github.com/revanced/revanced-patcher
synced 2025-09-13 18:30:49 +02:00
Compare commits
2 Commits
v20.0.1-de
...
v20.0.1-de
Author | SHA1 | Date | |
---|---|---|---|
![]() |
348d0070e7 | ||
![]() |
d53aacdad4 |
@@ -1,3 +1,10 @@
|
|||||||
|
## [20.0.1-dev.3](https://github.com/ReVanced/revanced-patcher/compare/v20.0.1-dev.2...v20.0.1-dev.3) (2024-10-03)
|
||||||
|
|
||||||
|
|
||||||
|
### Performance Improvements
|
||||||
|
|
||||||
|
* Free memory earlier and remove negligible lookup maps ([d53aacd](https://github.com/ReVanced/revanced-patcher/commit/d53aacdad4ed3750ddae526fb307577ea36e6171))
|
||||||
|
|
||||||
## [20.0.1-dev.2](https://github.com/ReVanced/revanced-patcher/compare/v20.0.1-dev.1...v20.0.1-dev.2) (2024-10-01)
|
## [20.0.1-dev.2](https://github.com/ReVanced/revanced-patcher/compare/v20.0.1-dev.1...v20.0.1-dev.2) (2024-10-01)
|
||||||
|
|
||||||
## [20.0.1-dev.1](https://github.com/ReVanced/revanced-patcher/compare/v20.0.0...v20.0.1-dev.1) (2024-09-18)
|
## [20.0.1-dev.1](https://github.com/ReVanced/revanced-patcher/compare/v20.0.0...v20.0.1-dev.1) (2024-09-18)
|
||||||
|
@@ -1,3 +1,3 @@
|
|||||||
org.gradle.parallel = true
|
org.gradle.parallel = true
|
||||||
org.gradle.caching = true
|
org.gradle.caching = true
|
||||||
version = 20.0.1-dev.2
|
version = 20.0.1-dev.3
|
||||||
|
@@ -66,36 +66,15 @@ class Fingerprint internal constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: If only one string is necessary, why not use a single string for every fingerprint?
|
// TODO: If only one string is necessary, why not use a single string for every fingerprint?
|
||||||
fun Fingerprint.lookupByStrings() = strings?.firstNotNullOfOrNull { lookupMaps.methodsByStrings[it] }
|
if (strings?.firstNotNullOfOrNull { lookupMaps.methodsByStrings[it] }?.let(::match) == true) {
|
||||||
if (lookupByStrings()?.let(::match) == true) {
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// No strings declared or none matched (partial matches are allowed).
|
context.classes.forEach { classDef ->
|
||||||
// Use signature matching.
|
if (match(context, classDef)) return true
|
||||||
fun Fingerprint.lookupBySignature(): MethodClassPairs {
|
|
||||||
if (accessFlags == null) return lookupMaps.allMethods
|
|
||||||
|
|
||||||
var returnTypeValue = returnType
|
|
||||||
if (returnTypeValue == null) {
|
|
||||||
if (AccessFlags.CONSTRUCTOR.isSet(accessFlags)) {
|
|
||||||
// Constructors always have void return type.
|
|
||||||
returnTypeValue = "V"
|
|
||||||
} else {
|
|
||||||
return lookupMaps.allMethods
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val signature =
|
return false
|
||||||
buildString {
|
|
||||||
append(accessFlags)
|
|
||||||
append(returnTypeValue.first())
|
|
||||||
appendParameters(parameters ?: return@buildString)
|
|
||||||
}
|
|
||||||
|
|
||||||
return lookupMaps.methodsBySignature[signature] ?: return MethodClassPairs()
|
|
||||||
}
|
|
||||||
return match(lookupBySignature())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -98,14 +98,12 @@ class Patcher(private val config: PatcherConfig) : Closeable {
|
|||||||
|
|
||||||
logger.info("Merging extensions")
|
logger.info("Merging extensions")
|
||||||
|
|
||||||
context.executablePatches.forEachRecursively { patch ->
|
with(context.bytecodeContext) {
|
||||||
if (patch is BytecodePatch && patch.extension != null) {
|
context.executablePatches.mergeExtensions()
|
||||||
context.bytecodeContext.merge(patch.extension)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize lookup maps.
|
// Initialize lookup maps.
|
||||||
context.bytecodeContext.lookupMaps
|
lookupMaps
|
||||||
|
}
|
||||||
|
|
||||||
logger.info("Executing patches")
|
logger.info("Executing patches")
|
||||||
|
|
||||||
|
@@ -20,6 +20,7 @@ class PatcherConfig(
|
|||||||
private val temporaryFilesPath: File = File("revanced-temporary-files"),
|
private val temporaryFilesPath: File = File("revanced-temporary-files"),
|
||||||
aaptBinaryPath: String? = null,
|
aaptBinaryPath: String? = null,
|
||||||
frameworkFileDirectory: String? = null,
|
frameworkFileDirectory: String? = null,
|
||||||
|
@Deprecated("This is going to be removed in the future because it is not needed anymore.")
|
||||||
internal val multithreadingDexFileWriter: Boolean = false,
|
internal val multithreadingDexFileWriter: Boolean = false,
|
||||||
) {
|
) {
|
||||||
private val logger = Logger.getLogger(PatcherConfig::class.java.name)
|
private val logger = Logger.getLogger(PatcherConfig::class.java.name)
|
||||||
|
@@ -21,7 +21,6 @@ import lanchon.multidexlib2.MultiDexIO
|
|||||||
import lanchon.multidexlib2.RawDexIO
|
import lanchon.multidexlib2.RawDexIO
|
||||||
import java.io.Closeable
|
import java.io.Closeable
|
||||||
import java.io.FileFilter
|
import java.io.FileFilter
|
||||||
import java.io.InputStream
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.logging.Logger
|
import java.util.logging.Logger
|
||||||
|
|
||||||
@@ -60,19 +59,18 @@ 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].
|
* Merge the extensions for this set of patches.
|
||||||
*/
|
*/
|
||||||
internal val classesByType = mutableMapOf<String, ClassDef>().apply {
|
internal fun Set<Patch<*>>.mergeExtensions() {
|
||||||
|
// 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) }
|
classes.forEach { classDef -> put(classDef.type, classDef) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
forEachRecursively { patch ->
|
||||||
* Merge an extension to [classes].
|
if (patch is BytecodePatch && patch.extension != null) {
|
||||||
*
|
|
||||||
* @param extensionInputStream The input stream of the extension to merge.
|
val extension = patch.extension.readAllBytes()
|
||||||
*/
|
|
||||||
internal fun merge(extensionInputStream: InputStream) {
|
|
||||||
val extension = extensionInputStream.readAllBytes()
|
|
||||||
|
|
||||||
RawDexIO.readRawDexFile(extension, 0, null).classes.forEach { classDef ->
|
RawDexIO.readRawDexFile(extension, 0, null).classes.forEach { classDef ->
|
||||||
val existingClass = classesByType[classDef.type] ?: run {
|
val existingClass = classesByType[classDef.type] ?: run {
|
||||||
@@ -97,6 +95,8 @@ class BytecodePatchContext internal constructor(private val config: PatcherConfi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find a class by its type using a contains check.
|
* Find a class by its type using a contains check.
|
||||||
@@ -145,6 +145,9 @@ class BytecodePatchContext internal constructor(private val config: PatcherConfi
|
|||||||
override fun get(): Set<PatcherResult.PatchedDexFile> {
|
override fun get(): Set<PatcherResult.PatchedDexFile> {
|
||||||
logger.info("Compiling patched dex files")
|
logger.info("Compiling patched dex files")
|
||||||
|
|
||||||
|
// Free up memory before compiling the dex files.
|
||||||
|
lookupMaps.close()
|
||||||
|
|
||||||
val patchedDexFileResults =
|
val patchedDexFileResults =
|
||||||
config.patchedFiles.resolve("dex").also {
|
config.patchedFiles.resolve("dex").also {
|
||||||
it.deleteRecursively() // Make sure the directory is empty.
|
it.deleteRecursively() // Make sure the directory is empty.
|
||||||
@@ -178,21 +181,6 @@ class BytecodePatchContext internal constructor(private val config: PatcherConfi
|
|||||||
* @param classes The list of classes to create the lookup maps from.
|
* @param classes The list of classes to create the lookup maps from.
|
||||||
*/
|
*/
|
||||||
internal class LookupMaps internal constructor(classes: List<ClassDef>) : Closeable {
|
internal class LookupMaps internal constructor(classes: List<ClassDef>) : Closeable {
|
||||||
/**
|
|
||||||
* Classes associated by their type.
|
|
||||||
*/
|
|
||||||
internal val classesByType = classes.associateBy { it.type }.toMutableMap()
|
|
||||||
|
|
||||||
/**
|
|
||||||
* All methods and the class they are a member of.
|
|
||||||
*/
|
|
||||||
internal val allMethods = MethodClassPairs()
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Methods associated by its access flags, return type and parameter.
|
|
||||||
*/
|
|
||||||
internal val methodsBySignature = MethodClassPairsLookupMap()
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Methods associated by strings referenced in it.
|
* Methods associated by strings referenced in it.
|
||||||
*/
|
*/
|
||||||
@@ -203,22 +191,6 @@ class BytecodePatchContext internal constructor(private val config: PatcherConfi
|
|||||||
classDef.methods.forEach { method ->
|
classDef.methods.forEach { method ->
|
||||||
val methodClassPair: MethodClassPair = method to classDef
|
val methodClassPair: MethodClassPair = method to classDef
|
||||||
|
|
||||||
// For fingerprints with no access or return type specified.
|
|
||||||
allMethods += methodClassPair
|
|
||||||
|
|
||||||
val accessFlagsReturnKey = method.accessFlags.toString() + method.returnType.first()
|
|
||||||
|
|
||||||
// Add <access><returnType> as the key.
|
|
||||||
methodsBySignature[accessFlagsReturnKey] = methodClassPair
|
|
||||||
|
|
||||||
// Add <access><returnType>[parameters] as the key.
|
|
||||||
methodsBySignature[
|
|
||||||
buildString {
|
|
||||||
append(accessFlagsReturnKey)
|
|
||||||
appendParameters(method.parameterTypes)
|
|
||||||
},
|
|
||||||
] = methodClassPair
|
|
||||||
|
|
||||||
// Add strings contained in the method as the key.
|
// Add strings contained in the method as the key.
|
||||||
method.instructionsOrNull?.forEach instructions@{ instruction ->
|
method.instructionsOrNull?.forEach instructions@{ instruction ->
|
||||||
if (instruction.opcode != Opcode.CONST_STRING && instruction.opcode != Opcode.CONST_STRING_JUMBO) {
|
if (instruction.opcode != Opcode.CONST_STRING && instruction.opcode != Opcode.CONST_STRING_JUMBO) {
|
||||||
@@ -259,15 +231,12 @@ class BytecodePatchContext internal constructor(private val config: PatcherConfi
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun close() {
|
override fun close() {
|
||||||
allMethods.clear()
|
|
||||||
methodsBySignature.clear()
|
|
||||||
methodsByStrings.clear()
|
methodsByStrings.clear()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun close() {
|
override fun close() {
|
||||||
lookupMaps.close()
|
lookupMaps.close()
|
||||||
classesByType.clear()
|
|
||||||
classes.clear()
|
classes.clear()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -6,7 +6,9 @@ import app.revanced.patcher.util.ProxyClassList
|
|||||||
import com.android.tools.smali.dexlib2.immutable.ImmutableClassDef
|
import com.android.tools.smali.dexlib2.immutable.ImmutableClassDef
|
||||||
import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
|
import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
|
||||||
import io.mockk.every
|
import io.mockk.every
|
||||||
|
import io.mockk.just
|
||||||
import io.mockk.mockk
|
import io.mockk.mockk
|
||||||
|
import io.mockk.runs
|
||||||
import kotlinx.coroutines.flow.toList
|
import kotlinx.coroutines.flow.toList
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import org.junit.jupiter.api.BeforeEach
|
import org.junit.jupiter.api.BeforeEach
|
||||||
@@ -193,6 +195,7 @@ internal object PatcherTest {
|
|||||||
private operator fun Set<Patch<*>>.invoke(): List<PatchResult> {
|
private operator fun Set<Patch<*>>.invoke(): List<PatchResult> {
|
||||||
every { patcher.context.executablePatches } returns toMutableSet()
|
every { patcher.context.executablePatches } returns toMutableSet()
|
||||||
every { patcher.context.bytecodeContext.lookupMaps } returns LookupMaps(patcher.context.bytecodeContext.classes)
|
every { patcher.context.bytecodeContext.lookupMaps } returns LookupMaps(patcher.context.bytecodeContext.classes)
|
||||||
|
every { with(patcher.context.bytecodeContext) { any<Set<Patch<*>>>().mergeExtensions() } } just runs
|
||||||
|
|
||||||
return runBlocking { patcher().toList() }
|
return runBlocking { patcher().toList() }
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user