1
mirror of https://github.com/revanced/revanced-patcher synced 2025-09-10 05:30:49 +02:00

Compare commits

...

23 Commits

Author SHA1 Message Date
semantic-release-bot
6d83a720cd chore(release): 14.2.0 [skip ci]
# [14.2.0](https://github.com/ReVanced/revanced-patcher/compare/v14.1.0...v14.2.0) (2023-08-27)

### Features

* load patches in lexicographical order ([e8f2087](e8f2087a6f))
* log when merging integrations ([983563e](983563efb6))

### Performance Improvements

* compare types of classes ([55d6945](55d694579a))
2023-08-27 00:55:36 +00:00
oSumAtrIX
8d0dd9c448 chore: merge branch dev to main (#222) 2023-08-27 02:53:47 +02:00
oSumAtrIX
64020eec49 chore: add multi-threading opportunity notice 2023-08-26 20:58:19 +02:00
semantic-release-bot
4dedfb85cb chore(release): 14.2.0-dev.3 [skip ci]
# [14.2.0-dev.3](https://github.com/ReVanced/revanced-patcher/compare/v14.2.0-dev.2...v14.2.0-dev.3) (2023-08-26)

### Performance Improvements

* compare types of classes ([55d6945](55d694579a))
2023-08-26 17:44:12 +00:00
oSumAtrIX
55d694579a perf: compare types of classes 2023-08-26 19:42:33 +02:00
semantic-release-bot
86db64edff chore(release): 14.2.0-dev.2 [skip ci]
# [14.2.0-dev.2](https://github.com/ReVanced/revanced-patcher/compare/v14.2.0-dev.1...v14.2.0-dev.2) (2023-08-26)

### Features

* log when merging integrations ([983563e](983563efb6))
2023-08-26 17:16:08 +00:00
oSumAtrIX
983563efb6 feat: log when merging integrations 2023-08-26 19:14:29 +02:00
oSumAtrIX
37abb2db99 build: package the Java sources 2023-08-26 19:10:29 +02:00
semantic-release-bot
5ba0b47e60 chore(release): 14.2.0-dev.1 [skip ci]
# [14.2.0-dev.1](https://github.com/ReVanced/revanced-patcher/compare/v14.1.0...v14.2.0-dev.1) (2023-08-25)

### Features

* load patches in lexicographical order ([e8f2087](e8f2087a6f))
2023-08-25 15:12:46 +00:00
oSumAtrIX
e8f2087a6f feat: load patches in lexicographical order
This feature was lost in past commits
2023-08-25 17:10:44 +02:00
semantic-release-bot
6ce99f5cdf chore(release): 14.1.0 [skip ci]
# [14.1.0](https://github.com/ReVanced/revanced-patcher/compare/v14.0.0...v14.1.0) (2023-08-24)

### Bug Fixes

* move version properties file to correct package ([e985676](e985676c2d))

### Features

* properly make use of logging facade ([ba56a6a](ba56a6a2ee))
2023-08-24 02:50:15 +00:00
oSumAtrIX
13c0c9cdd3 chore: merge branch dev to main (#220) 2023-08-24 04:48:39 +02:00
semantic-release-bot
58ffdb60d7 chore(release): 14.1.0-dev.1 [skip ci]
# [14.1.0-dev.1](https://github.com/ReVanced/revanced-patcher/compare/v14.0.1-dev.1...v14.1.0-dev.1) (2023-08-24)

### Features

* properly make use of logging facade ([ba56a6a](ba56a6a2ee))
2023-08-24 02:45:16 +00:00
oSumAtrIX
ba56a6a2ee feat: properly make use of logging facade
This deprecates the primary constructor of `PatcherOptions` with the `logger` parameter
2023-08-24 04:43:16 +02:00
oSumAtrIX
ccccf5b1d2 build: migrate dependencies to version catalogs 2023-08-23 04:30:31 +02:00
semantic-release-bot
b507ac0a54 chore(release): 14.0.1-dev.1 [skip ci]
## [14.0.1-dev.1](https://github.com/ReVanced/revanced-patcher/compare/v14.0.0...v14.0.1-dev.1) (2023-08-23)

### Bug Fixes

* move version properties file to correct package ([e985676](e985676c2d))
2023-08-23 01:39:26 +00:00
oSumAtrIX
e985676c2d fix: move version properties file to correct package 2023-08-23 03:36:48 +02:00
oSumAtrIX
f7f4ba6c55 build: update dependencies 2023-08-23 03:36:48 +02:00
semantic-release-bot
4292f43814 chore(release): 14.0.0 [skip ci]
# [14.0.0](https://github.com/ReVanced/revanced-patcher/compare/v13.0.0...v14.0.0) (2023-08-22)

### Bug Fixes

* log decoding resources after logging deleting resource cache directory ([db62a16](db62a1607b))
* only emit closed patches that did not throw an exception with the `@Patch` annotation ([5938f6b](5938f6b7ea))
* supply the parent classloader to `DexClassLoader` ([0f15077](0f15077225))

### Code Refactoring

* improve structure and public API ([6b8977f](6b8977f178))

### Features

* do not log instantiation of ReVanced Patcher ([273dd8d](273dd8d388))

### BREAKING CHANGES

* Various public APIs have been changed. The `Version` annotation has been removed. Patches do not return anything anymore and instead throw `PatchException`. Multiple patch bundles can now be loaded in a single ClassLoader to bypass class loader isolation.
2023-08-22 17:16:51 +00:00
oSumAtrIX
30bd4fd9fe chore: merge branch dev to main (#217) 2023-08-22 19:15:09 +02:00
semantic-release-bot
76de39369d chore(release): 14.0.0-dev.4 [skip ci]
# [14.0.0-dev.4](https://github.com/ReVanced/revanced-patcher/compare/v14.0.0-dev.3...v14.0.0-dev.4) (2023-08-22)

### Bug Fixes

* only emit closed patches that did not throw an exception with the `@Patch` annotation ([5938f6b](5938f6b7ea))
2023-08-22 17:04:25 +00:00
oSumAtrIX
88a703ce36 build: bump dependencies 2023-08-22 19:01:59 +02:00
oSumAtrIX
5938f6b7ea fix: only emit closed patches that did not throw an exception with the @Patch annotation 2023-08-22 19:00:34 +02:00
14 changed files with 243 additions and 87 deletions

View File

@@ -1,3 +1,94 @@
# [14.2.0](https://github.com/ReVanced/revanced-patcher/compare/v14.1.0...v14.2.0) (2023-08-27)
### Features
* load patches in lexicographical order ([e8f2087](https://github.com/ReVanced/revanced-patcher/commit/e8f2087a6ffa6077fb3a6a69e29f3aec72e2fc1b))
* log when merging integrations ([983563e](https://github.com/ReVanced/revanced-patcher/commit/983563efb6d7c8d289464b8bf71a016b8a735630))
### Performance Improvements
* compare types of classes ([55d6945](https://github.com/ReVanced/revanced-patcher/commit/55d694579ac2718b9e2c61ca5f38419c3775ef87))
# [14.2.0-dev.3](https://github.com/ReVanced/revanced-patcher/compare/v14.2.0-dev.2...v14.2.0-dev.3) (2023-08-26)
### Performance Improvements
* compare types of classes ([55d6945](https://github.com/ReVanced/revanced-patcher/commit/55d694579ac2718b9e2c61ca5f38419c3775ef87))
# [14.2.0-dev.2](https://github.com/ReVanced/revanced-patcher/compare/v14.2.0-dev.1...v14.2.0-dev.2) (2023-08-26)
### Features
* log when merging integrations ([983563e](https://github.com/ReVanced/revanced-patcher/commit/983563efb6d7c8d289464b8bf71a016b8a735630))
# [14.2.0-dev.1](https://github.com/ReVanced/revanced-patcher/compare/v14.1.0...v14.2.0-dev.1) (2023-08-25)
### Features
* load patches in lexicographical order ([e8f2087](https://github.com/ReVanced/revanced-patcher/commit/e8f2087a6ffa6077fb3a6a69e29f3aec72e2fc1b))
# [14.1.0](https://github.com/ReVanced/revanced-patcher/compare/v14.0.0...v14.1.0) (2023-08-24)
### Bug Fixes
* move version properties file to correct package ([e985676](https://github.com/ReVanced/revanced-patcher/commit/e985676c2d8e5d6cb907d371de30428caaa6da43))
### Features
* properly make use of logging facade ([ba56a6a](https://github.com/ReVanced/revanced-patcher/commit/ba56a6a2eef503c0d6cdd846ddce2e1474d8ed1a))
# [14.1.0-dev.1](https://github.com/ReVanced/revanced-patcher/compare/v14.0.1-dev.1...v14.1.0-dev.1) (2023-08-24)
### Features
* properly make use of logging facade ([ba56a6a](https://github.com/ReVanced/revanced-patcher/commit/ba56a6a2eef503c0d6cdd846ddce2e1474d8ed1a))
## [14.0.1-dev.1](https://github.com/ReVanced/revanced-patcher/compare/v14.0.0...v14.0.1-dev.1) (2023-08-23)
### Bug Fixes
* move version properties file to correct package ([e985676](https://github.com/ReVanced/revanced-patcher/commit/e985676c2d8e5d6cb907d371de30428caaa6da43))
# [14.0.0](https://github.com/ReVanced/revanced-patcher/compare/v13.0.0...v14.0.0) (2023-08-22)
### Bug Fixes
* log decoding resources after logging deleting resource cache directory ([db62a16](https://github.com/ReVanced/revanced-patcher/commit/db62a1607b4a9d6256b5f5153decb088d9680553))
* only emit closed patches that did not throw an exception with the `@Patch` annotation ([5938f6b](https://github.com/ReVanced/revanced-patcher/commit/5938f6b7ea25103a0a1b56ceebe49139bc80c6f5))
* supply the parent classloader to `DexClassLoader` ([0f15077](https://github.com/ReVanced/revanced-patcher/commit/0f15077225600b65200022c1a318e504deb472b9))
### Code Refactoring
* improve structure and public API ([6b8977f](https://github.com/ReVanced/revanced-patcher/commit/6b8977f17854ef0344d868e6391cb18134eceadc))
### Features
* do not log instantiation of ReVanced Patcher ([273dd8d](https://github.com/ReVanced/revanced-patcher/commit/273dd8d388f8e9b7436c6d6145a94c12c1fabe55))
### BREAKING CHANGES
* Various public APIs have been changed. The `Version` annotation has been removed. Patches do not return anything anymore and instead throw `PatchException`. Multiple patch bundles can now be loaded in a single ClassLoader to bypass class loader isolation.
# [14.0.0-dev.4](https://github.com/ReVanced/revanced-patcher/compare/v14.0.0-dev.3...v14.0.0-dev.4) (2023-08-22)
### Bug Fixes
* only emit closed patches that did not throw an exception with the `@Patch` annotation ([5938f6b](https://github.com/ReVanced/revanced-patcher/commit/5938f6b7ea25103a0a1b56ceebe49139bc80c6f5))
# [14.0.0-dev.3](https://github.com/ReVanced/revanced-patcher/compare/v14.0.0-dev.2...v14.0.0-dev.3) (2023-08-20) # [14.0.0-dev.3](https://github.com/ReVanced/revanced-patcher/compare/v14.0.0-dev.2...v14.0.0-dev.3) (2023-08-20)

View File

@@ -5,35 +5,17 @@ plugins {
group = "app.revanced" group = "app.revanced"
val githubUsername: String = project.findProperty("gpr.user") as? String ?: System.getenv("GITHUB_ACTOR")
val githubPassword: String = project.findProperty("gpr.key") as? String ?: System.getenv("GITHUB_TOKEN")
repositories {
mavenCentral()
google()
mavenLocal()
listOf("multidexlib2", "apktool").forEach { repo ->
maven {
url = uri("https://maven.pkg.github.com/revanced/$repo")
credentials {
username = githubUsername
password = githubPassword
}
}
}
}
dependencies { dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1") implementation(libs.kotlinx.coroutines.core)
implementation("xpp3:xpp3:1.1.4c") implementation(libs.xpp3)
implementation("com.android.tools.smali:smali:3.0.3") implementation(libs.smali)
implementation("app.revanced:multidexlib2:3.0.3.r2") implementation(libs.multidexlib2)
implementation("app.revanced:apktool-lib:2.8.2-4") implementation(libs.apktool.lib)
implementation("org.jetbrains.kotlin:kotlin-reflect:1.8.22") implementation(libs.kotlin.reflect)
compileOnly("com.google.android:android:4.1.1.4") compileOnly(libs.android)
testImplementation("org.jetbrains.kotlin:kotlin-test:1.8.20-RC") testImplementation(libs.kotlin.test)
} }
tasks { tasks {
@@ -43,35 +25,32 @@ tasks {
events("PASSED", "SKIPPED", "FAILED") events("PASSED", "SKIPPED", "FAILED")
} }
} }
processResources { processResources {
expand("projectVersion" to project.version) expand("projectVersion" to project.version)
} }
} }
kotlin { jvmToolchain(11) }
java { java {
withSourcesJar() withSourcesJar()
} }
kotlin {
jvmToolchain(11)
}
publishing { publishing {
repositories { repositories {
if (System.getenv("GITHUB_ACTOR") != null) mavenLocal()
maven { maven {
name = "GitHubPackages" name = "GitHubPackages"
url = uri("https://maven.pkg.github.com/revanced/revanced-patcher") url = uri("https://maven.pkg.github.com/revanced/revanced-patcher")
credentials { credentials {
username = System.getenv("GITHUB_ACTOR") username = System.getenv("GITHUB_ACTOR")
password = System.getenv("GITHUB_TOKEN") password = System.getenv("GITHUB_TOKEN")
}
} }
else }
mavenLocal()
} }
publications { publications {
register<MavenPublication>("gpr") { create<MavenPublication>("gpr") {
from(components["java"]) from(components["java"])
} }
} }

View File

@@ -1,4 +1,4 @@
org.gradle.parallel = true org.gradle.parallel = true
org.gradle.caching = true org.gradle.caching = true
kotlin.code.style = official kotlin.code.style = official
version = 14.0.0-dev.3 version = 14.2.0

21
gradle/libs.versions.toml Normal file
View File

@@ -0,0 +1,21 @@
[versions]
android = "4.1.1.4"
kotlin-reflect = "1.9.0"
apktool-lib = "2.8.2-5"
kotlin-test = "1.8.20-RC"
kotlinx-coroutines-core = "1.7.1"
multidexlib2 = "3.0.3.r2"
shadow = "8.1.1"
smali = "3.0.3"
xpp3 = "1.1.4c"
[libraries]
android = { module = "com.google.android:android", version.ref = "android" }
kotlin-reflect = { module = "org.jetbrains.kotlin:kotlin-reflect", version.ref = "kotlin-reflect" }
apktool-lib = { module = "app.revanced:apktool-lib", version.ref = "apktool-lib" }
kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin-test" }
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx-coroutines-core" }
multidexlib2 = { module = "app.revanced:multidexlib2", version.ref = "multidexlib2" }
smali = { module = "com.android.tools.smali:smali", version.ref = "smali" }
xpp3 = { module = "xpp3:xpp3", version.ref = "xpp3" }

View File

@@ -1 +1,22 @@
val githubUsername: String = providers.gradleProperty("gpr.user").orNull ?: System.getenv("GITHUB_ACTOR")
val githubPassword: String = providers.gradleProperty("gpr.key").orNull ?: System.getenv("GITHUB_TOKEN")
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
mavenCentral()
google()
mavenLocal()
listOf("multidexlib2", "apktool").forEach { repo ->
maven {
url = uri("https://maven.pkg.github.com/revanced/$repo")
credentials {
username = githubUsername
password = githubPassword
}
}
}
}
}
rootProject.name = "revanced-patcher" rootProject.name = "revanced-patcher"

View File

@@ -3,6 +3,7 @@
package app.revanced.patcher package app.revanced.patcher
import app.revanced.patcher.extensions.AnnotationExtensions.findAnnotationRecursively import app.revanced.patcher.extensions.AnnotationExtensions.findAnnotationRecursively
import app.revanced.patcher.extensions.PatchExtensions.patchName
import app.revanced.patcher.patch.Patch import app.revanced.patcher.patch.Patch
import app.revanced.patcher.patch.PatchClass import app.revanced.patcher.patch.PatchClass
import dalvik.system.DexClassLoader import dalvik.system.DexClassLoader
@@ -28,6 +29,8 @@ sealed class PatchBundleLoader private constructor(
}.map { }.map {
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
it as PatchClass it as PatchClass
}.sortedBy {
it.patchName
}.let { addAll(it) } }.let { addAll(it) }
} }

View File

@@ -2,6 +2,7 @@ package app.revanced.patcher
import app.revanced.patcher.data.Context import app.revanced.patcher.data.Context
import app.revanced.patcher.data.ResourceContext import app.revanced.patcher.data.ResourceContext
import app.revanced.patcher.extensions.AnnotationExtensions.findAnnotationRecursively
import app.revanced.patcher.extensions.PatchExtensions.dependencies import app.revanced.patcher.extensions.PatchExtensions.dependencies
import app.revanced.patcher.extensions.PatchExtensions.patchName import app.revanced.patcher.extensions.PatchExtensions.patchName
import app.revanced.patcher.extensions.PatchExtensions.requiresIntegrations import app.revanced.patcher.extensions.PatchExtensions.requiresIntegrations
@@ -14,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.
@@ -23,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.
@@ -158,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.
@@ -202,7 +206,15 @@ class Patcher(
) )
if (returnOnError) return@flow if (returnOnError) return@flow
} ?: emit(result) } ?: run {
executedPatch
.patchInstance::class
.java
.findAnnotationRecursively(app.revanced.patcher.patch.annotations.Patch::class)
?: return@run
emit(result)
}
} }
} }

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].
@@ -104,6 +107,9 @@ class BytecodeContext internal constructor(private val options: PatcherOptions)
override fun flush() { override fun flush() {
if (!merge) return if (!merge) return
logger.info("Merging integrations")
// TODO: Multi-thread this.
this@Integrations.forEach { integrations -> this@Integrations.forEach { integrations ->
MultiDexIO.readDexFile( MultiDexIO.readDexFile(
true, true,
@@ -111,15 +117,15 @@ class BytecodeContext internal constructor(private val options: PatcherOptions)
null, null,
null null
).classes.forEach classDef@{ classDef -> ).classes.forEach classDef@{ classDef ->
val existingClass = classes.find { it == classDef } ?: run { val existingClass = classes.find { it.type == classDef.type } ?: 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 +143,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].