Skip to content

Commit

Permalink
chore: Lint code
Browse files Browse the repository at this point in the history
  • Loading branch information
oSumAtrIX committed Nov 26, 2023
1 parent 287841d commit 80407b6
Show file tree
Hide file tree
Showing 57 changed files with 1,037 additions and 817 deletions.
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,4 @@ publishing {
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ import java.io.File
@FunctionalInterface
interface IntegrationsConsumer {
fun acceptIntegrations(integrations: List<File>)
}
}
38 changes: 23 additions & 15 deletions src/main/kotlin/app/revanced/patcher/PatchBundleLoader.kt
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ sealed class PatchBundleLoader private constructor(
// This constructor parameter is unfortunately necessary,
// so that a reference to the mutable set is present in the constructor to be able to add patches to it.
// because the instance itself is a PatchSet, which is immutable, that is delegated by the parameter.
private val patchSet: MutableSet<Patch<*>> = mutableSetOf()
private val patchSet: MutableSet<Patch<*>> = mutableSetOf(),
) : PatchSet by patchSet {
private val logger = Logger.getLogger(PatchBundleLoader::class.java.name)

Expand All @@ -63,22 +63,29 @@ sealed class PatchBundleLoader private constructor(
* @param silent Whether to suppress logging.
* @return The instantiated [Patch] or `null` if the [Patch] could not be instantiated.
*/
internal fun Class<*>.getInstance(logger: Logger, silent: Boolean = false): Patch<*>? {
internal fun Class<*>.getInstance(
logger: Logger,
silent: Boolean = false,
): Patch<*>? {
return try {
getField("INSTANCE").get(null)
} catch (exception: NoSuchFieldException) {
if (!silent) logger.fine(
"Patch class '${name}' has no INSTANCE field, therefor not a singleton. " +
"Will try to instantiate it."
)
if (!silent) {
logger.fine(
"Patch class '$name' has no INSTANCE field, therefor not a singleton. " +
"Will try to instantiate it.",
)
}

try {
getDeclaredConstructor().newInstance()
} catch (exception: Exception) {
if (!silent) logger.severe(
"Patch class '${name}' is not singleton and has no suitable constructor, " +
"therefor cannot be instantiated and will be ignored."
)
if (!silent) {
logger.severe(
"Patch class '$name' is not singleton and has no suitable constructor, " +
"therefor cannot be instantiated and will be ignored.",
)
}

return null
}
Expand All @@ -97,7 +104,7 @@ sealed class PatchBundleLoader private constructor(
{ patchBundle ->
JarFile(patchBundle).entries().toList().filter { it.name.endsWith(".class") }
.map { it.name.replace('/', '.').replace(".class", "") }
}
},
)

/**
Expand All @@ -109,19 +116,20 @@ sealed class PatchBundleLoader private constructor(
*/
class Dex(vararg patchBundles: File, optimizedDexDirectory: File? = null) : PatchBundleLoader(
DexClassLoader(
patchBundles.joinToString(File.pathSeparator) { it.absolutePath }, optimizedDexDirectory?.absolutePath,
patchBundles.joinToString(File.pathSeparator) { it.absolutePath },
optimizedDexDirectory?.absolutePath,
null,
PatchBundleLoader::class.java.classLoader
PatchBundleLoader::class.java.classLoader,
),
patchBundles,
{ patchBundle ->
MultiDexIO.readDexFile(true, patchBundle, BasicDexFileNamer(), null, null).classes
.map { classDef ->
classDef.type.substring(1, classDef.length - 1)
}
}
},
) {
@Deprecated("This constructor is deprecated. Use the constructor with the second parameter instead.")
constructor(vararg patchBundles: File) : this(*patchBundles, optimizedDexDirectory = null)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ import kotlinx.coroutines.flow.Flow
import java.util.function.Function

@FunctionalInterface
interface PatchExecutorFunction : Function<Boolean, Flow<PatchResult>>
interface PatchExecutorFunction : Function<Boolean, Flow<PatchResult>>
221 changes: 112 additions & 109 deletions src/main/kotlin/app/revanced/patcher/Patcher.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import java.util.logging.Logger
* @param options The options for the patcher.
*/
class Patcher(
private val options: PatcherOptions
private val options: PatcherOptions,
) : PatchExecutorFunction, PatchesConsumer, IntegrationsConsumer, Supplier<PatcherResult>, Closeable {
private val logger = Logger.getLogger(Patcher::class.java.name)

Expand All @@ -39,11 +39,12 @@ class Patcher(
// * @param patches The [Patch]es to add.
// * @throws PatcherException.CircularDependencyException If a circular dependency is detected.
// */

/**
* Add [Patch]es to ReVanced [Patcher].
*
* @param patches The [Patch]es to add.
*/
*/
@Suppress("NAME_SHADOWING")
override fun acceptPatches(patches: List<Patch<*>>) {
/**
Expand Down Expand Up @@ -82,7 +83,7 @@ class Patcher(
dependency.visit()
}
}
*/
*/

/**
* Returns true if at least one patch or its dependencies matches the given predicate.
Expand Down Expand Up @@ -126,128 +127,130 @@ class Patcher(
* @param returnOnError If true, ReVanced [Patcher] will return immediately if a [Patch] fails.
* @return A pair of the name of the [Patch] and its [PatchResult].
*/
override fun apply(returnOnError: Boolean) = flow {
override fun apply(returnOnError: Boolean) =
flow {
/**
* Execute a [Patch] and its dependencies recursively.
*
* @param patch The [Patch] to execute.
* @param executedPatches A map to prevent [Patch]es from being executed twice due to dependencies.
* @return The result of executing the [Patch].
*/
fun executePatch(
patch: Patch<*>,
executedPatches: LinkedHashMap<Patch<*>, PatchResult>,
): PatchResult {
val patchName = patch.name ?: patch.toString()

executedPatches[patch]?.let { patchResult ->
patchResult.exception ?: return patchResult

// Return a new result with an exception indicating that the patch was not executed previously,
// because it is a dependency of another patch that failed.
return PatchResult(patch, PatchException("'$patchName' did not succeed previously"))
}

/**
* Execute a [Patch] and its dependencies recursively.
*
* @param patch The [Patch] to execute.
* @param executedPatches A map to prevent [Patch]es from being executed twice due to dependencies.
* @return The result of executing the [Patch].
*/
fun executePatch(
patch: Patch<*>,
executedPatches: LinkedHashMap<Patch<*>, PatchResult>
): PatchResult {
val patchName = patch.name ?: patch.toString()

executedPatches[patch]?.let { patchResult ->
patchResult.exception ?: return patchResult

// Return a new result with an exception indicating that the patch was not executed previously,
// because it is a dependency of another patch that failed.
return PatchResult(patch, PatchException("'$patchName' did not succeed previously"))
}
// Recursively execute all dependency patches.
patch.dependencies?.forEach { dependencyClass ->
val dependency = context.allPatches[dependencyClass]!!
val result = executePatch(dependency, executedPatches)

// Recursively execute all dependency patches.
patch.dependencies?.forEach { dependencyClass ->
val dependency = context.allPatches[dependencyClass]!!
val result = executePatch(dependency, executedPatches)

result.exception?.let {
return PatchResult(
patch,
PatchException(
"'$patchName' depends on '${dependency.name ?: dependency}' " +
"that raised an exception:\n${it.stackTraceToString()}"
result.exception?.let {
return PatchResult(
patch,
PatchException(
"'$patchName' depends on '${dependency.name ?: dependency}' " +
"that raised an exception:\n${it.stackTraceToString()}",
),
)
)
}
}

return try {
// TODO: Implement this in a more polymorphic way.
when (patch) {
is BytecodePatch -> {
patch.fingerprints.resolveUsingLookupMap(context.bytecodeContext)
patch.execute(context.bytecodeContext)
}
is ResourcePatch -> {
patch.execute(context.resourceContext)
}
}

PatchResult(patch)
} catch (exception: PatchException) {
PatchResult(patch, exception)
} catch (exception: Exception) {
PatchResult(patch, PatchException(exception))
}.also { executedPatches[patch] = it }
}

if (context.bytecodeContext.integrations.merge) context.bytecodeContext.integrations.flush()

LookupMap.initializeLookupMaps(context.bytecodeContext)
return try {
// TODO: Implement this in a more polymorphic way.
when (patch) {
is BytecodePatch -> {
patch.fingerprints.resolveUsingLookupMap(context.bytecodeContext)
patch.execute(context.bytecodeContext)
}
is ResourcePatch -> {
patch.execute(context.resourceContext)
}
}

// Prevent from decoding the app manifest twice if it is not needed.
if (options.resourceDecodingMode == ResourceContext.ResourceDecodingMode.FULL)
context.resourceContext.decodeResources(ResourceContext.ResourceDecodingMode.FULL)
PatchResult(patch)
} catch (exception: PatchException) {
PatchResult(patch, exception)
} catch (exception: Exception) {
PatchResult(patch, PatchException(exception))
}.also { executedPatches[patch] = it }
}

logger.info("Executing patches")
if (context.bytecodeContext.integrations.merge) context.bytecodeContext.integrations.flush()

val executedPatches = LinkedHashMap<Patch<*>, PatchResult>() // Key is name.
LookupMap.initializeLookupMaps(context.bytecodeContext)

context.executablePatches.values.sortedBy { it.name }.forEach { patch ->
val patchResult = executePatch(patch, executedPatches)
// Prevent from decoding the app manifest twice if it is not needed.
if (options.resourceDecodingMode == ResourceContext.ResourceDecodingMode.FULL) {
context.resourceContext.decodeResources(ResourceContext.ResourceDecodingMode.FULL)
}

// If the patch failed, emit the result, even if it is closeable.
// Results of executed patches that are closeable will be emitted later.
patchResult.exception?.let {
// Propagate exception to caller instead of wrapping it in a new exception.
emit(patchResult)
logger.info("Executing patches")

if (returnOnError) return@flow
} ?: run {
if (patch is Closeable) return@run
val executedPatches = LinkedHashMap<Patch<*>, PatchResult>() // Key is name.

emit(patchResult)
}
}
context.executablePatches.values.sortedBy { it.name }.forEach { patch ->
val patchResult = executePatch(patch, executedPatches)

executedPatches.values
.filter { it.exception == null }
.filter { it.patch is Closeable }.asReversed().forEach { executedPatch ->
val patch = executedPatch.patch
// If the patch failed, emit the result, even if it is closeable.
// Results of executed patches that are closeable will be emitted later.
patchResult.exception?.let {
// Propagate exception to caller instead of wrapping it in a new exception.
emit(patchResult)

val result = try {
(patch as Closeable).close()
if (returnOnError) return@flow
} ?: run {
if (patch is Closeable) return@run

executedPatch
} catch (exception: PatchException) {
PatchResult(patch, exception)
} catch (exception: Exception) {
PatchResult(patch, PatchException(exception))
emit(patchResult)
}
}

result.exception?.let {
emit(
PatchResult(
patch,
PatchException(
"'${patch.name}' raised an exception while being closed: ${it.stackTraceToString()}",
result.exception
)
executedPatches.values
.filter { it.exception == null }
.filter { it.patch is Closeable }.asReversed().forEach { executedPatch ->
val patch = executedPatch.patch

val result =
try {
(patch as Closeable).close()

executedPatch
} catch (exception: PatchException) {
PatchResult(patch, exception)
} catch (exception: Exception) {
PatchResult(patch, PatchException(exception))
}

result.exception?.let {
emit(
PatchResult(
patch,
PatchException(
"'${patch.name}' raised an exception while being closed: ${it.stackTraceToString()}",
result.exception,
),
),
)
)

if (returnOnError) return@flow
} ?: run {
patch.name ?: return@run
if (returnOnError) return@flow
} ?: run {
patch.name ?: return@run

emit(result)
emit(result)
}
}
}
}
}

override fun close() = LookupMap.clearLookupMaps()

Expand All @@ -256,10 +259,10 @@ class Patcher(
*
* @return The [PatcherResult] containing the patched input files.
*/
override fun get() = PatcherResult(
context.bytecodeContext.get(),
context.resourceContext.get(),
context.packageMetadata.apkInfo.doNotCompress?.toList()
)
override fun get() =
PatcherResult(
context.bytecodeContext.get(),
context.resourceContext.get(),
context.packageMetadata.apkInfo.doNotCompress?.toList(),
)
}

2 changes: 1 addition & 1 deletion src/main/kotlin/app/revanced/patcher/PatcherContext.kt
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,4 @@ class PatcherContext internal constructor(options: PatcherOptions) {
* This holds the current state of the bytecode.
*/
internal val bytecodeContext = BytecodeContext(options)
}
}
Loading

0 comments on commit 80407b6

Please sign in to comment.