Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

perf: increase efficiency by using coroutines #3885

Draft
wants to merge 3 commits into
base: dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ appcompat = "1.7.0"
okhttp = "5.0.0-alpha.14"
retrofit = "2.11.0"
guava = "33.2.1-jre"
kotlinx-corouiines = "1.9.0"

[libraries]
gson = { module = "com.google.code.gson:gson", version.ref = "gson" }
Expand All @@ -20,6 +21,7 @@ appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "a
okhttp = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttp" }
retrofit = { module = "com.squareup.retrofit2:retrofit", version.ref = "retrofit" }
guava = { module = "com.google.guava:guava", version.ref = "guava" }
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx-corouiines" }


[plugins]
Expand Down
16 changes: 8 additions & 8 deletions patches/api/patches.api
Original file line number Diff line number Diff line change
Expand Up @@ -533,7 +533,7 @@ public final class app/revanced/patches/shared/misc/checks/BaseCheckEnvironmentP

public final class app/revanced/patches/shared/misc/extension/ExtensionHook {
public final fun getFingerprint ()Lapp/revanced/patcher/Fingerprint;
public final fun invoke (Lapp/revanced/patcher/patch/BytecodePatchContext;Ljava/lang/String;)V
public final fun invoke (Lapp/revanced/patcher/patch/BytecodePatchContext;Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
}

public final class app/revanced/patches/shared/misc/extension/SharedExtensionPatchKt {
Expand Down Expand Up @@ -980,7 +980,7 @@ public final class app/revanced/patches/twitter/misc/hook/json/JsonHook {
}

public final class app/revanced/patches/twitter/misc/hook/json/JsonHookPatchKt {
public static final fun addJsonHook (Lapp/revanced/patcher/patch/BytecodePatchContext;Lapp/revanced/patches/twitter/misc/hook/json/JsonHook;)V
public static final fun addJsonHook (Lapp/revanced/patcher/patch/BytecodePatchContext;Lapp/revanced/patches/twitter/misc/hook/json/JsonHook;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public static final fun getJsonHookPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
}

Expand Down Expand Up @@ -1207,7 +1207,7 @@ public final class app/revanced/patches/youtube/layout/tablet/EnableTabletLayout

public final class app/revanced/patches/youtube/layout/theme/LithoColorHookPatchKt {
public static final fun getLithoColorHookPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
public static final fun getLithoColorOverrideHook ()Lkotlin/jvm/functions/Function2;
public static final fun getLithoColorOverrideHook ()Lkotlin/jvm/functions/Function3;
}

public final class app/revanced/patches/youtube/layout/theme/ThemePatchKt {
Expand Down Expand Up @@ -1288,10 +1288,10 @@ public final class app/revanced/patches/youtube/misc/litho/filter/LithoFilterPat
}

public final class app/revanced/patches/youtube/misc/navigation/NavigationBarHookPatchKt {
public static field hookNavigationButtonCreated Lkotlin/jvm/functions/Function1;
public static final fun getHookNavigationButtonCreated ()Lkotlin/jvm/functions/Function1;
public static field hookNavigationButtonCreated Lkotlin/jvm/functions/Function2;
public static final fun getHookNavigationButtonCreated ()Lkotlin/jvm/functions/Function2;
public static final fun getNavigationBarHookPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
public static final fun setHookNavigationButtonCreated (Lkotlin/jvm/functions/Function1;)V
public static final fun setHookNavigationButtonCreated (Lkotlin/jvm/functions/Function2;)V
}

public final class app/revanced/patches/youtube/misc/playercontrols/PlayerControlsPatchKt {
Expand Down Expand Up @@ -1433,7 +1433,7 @@ public final class app/revanced/util/BytecodeUtilsKt {
public static final fun findInstructionIndicesReversedOrThrow (Lcom/android/tools/smali/dexlib2/iface/Method;Lcom/android/tools/smali/dexlib2/Opcode;)Ljava/util/List;
public static final fun findInstructionIndicesReversedOrThrow (Lcom/android/tools/smali/dexlib2/iface/Method;Lkotlin/jvm/functions/Function1;)Ljava/util/List;
public static final fun findMutableMethodOf (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableClass;Lcom/android/tools/smali/dexlib2/iface/Method;)Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;
public static final fun forEachLiteralValueInstruction (Lapp/revanced/patcher/patch/BytecodePatchContext;JLkotlin/jvm/functions/Function2;)V
public static final fun forEachLiteralValueInstruction (Lapp/revanced/patcher/patch/BytecodePatchContext;JLkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public static final fun indexOfFirstInstruction (Lcom/android/tools/smali/dexlib2/iface/Method;ILcom/android/tools/smali/dexlib2/Opcode;)I
public static final fun indexOfFirstInstruction (Lcom/android/tools/smali/dexlib2/iface/Method;ILkotlin/jvm/functions/Function1;)I
public static final fun indexOfFirstInstruction (Lcom/android/tools/smali/dexlib2/iface/Method;Lcom/android/tools/smali/dexlib2/Opcode;)I
Expand Down Expand Up @@ -1463,7 +1463,7 @@ public final class app/revanced/util/BytecodeUtilsKt {
public static final fun returnEarly (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;Z)V
public static synthetic fun returnEarly$default (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;ZILjava/lang/Object;)V
public static final fun transformMethods (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableClass;Lkotlin/jvm/functions/Function1;)V
public static final fun traverseClassHierarchy (Lapp/revanced/patcher/patch/BytecodePatchContext;Lapp/revanced/patcher/util/proxy/mutableTypes/MutableClass;Lkotlin/jvm/functions/Function1;)V
public static final fun traverseClassHierarchy (Lapp/revanced/patcher/patch/BytecodePatchContext;Lapp/revanced/patcher/util/proxy/mutableTypes/MutableClass;Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
}

public final class app/revanced/util/ResourceGroup {
Expand Down
15 changes: 15 additions & 0 deletions patches/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,22 @@ patches {
}
}

repositories {
mavenLocal()
mavenCentral()
google()
maven {
// A repository must be specified for some reason. "registry" is a dummy.
url = uri("https://maven.pkg.github.com/revanced/registry")
credentials {
username = project.findProperty("gpr.user") as String? ?: System.getenv("GITHUB_ACTOR")
password = project.findProperty("gpr.key") as String? ?: System.getenv("GITHUB_TOKEN")
}
}
}

dependencies {
implementation(libs.kotlinx.coroutines.core)
// Used by JsonGenerator.
implementation(libs.gson)
// Required due to smali, or build fails. Can be removed once smali is bumped.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ import app.revanced.util.findMutableMethodOf
import com.android.tools.smali.dexlib2.iface.ClassDef
import com.android.tools.smali.dexlib2.iface.Method
import com.android.tools.smali.dexlib2.iface.instruction.Instruction
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.joinAll
import kotlinx.coroutines.launch

fun <T> transformInstructionsPatch(
filterMap: (ClassDef, Method, Instruction, Int) -> T?,
Expand All @@ -14,24 +17,34 @@ fun <T> transformInstructionsPatch(
// Returns the patch indices as a Sequence, which will execute lazily.
fun findPatchIndices(classDef: ClassDef, method: Method): Sequence<T>? =
method.implementation?.instructions?.asSequence()?.withIndex()?.mapNotNull { (index, instruction) ->
filterMap(classDef, method, instruction, index)
}
filterMap(classDef, method, instruction, index)
}

execute {
// Find all methods to patch
buildMap {
classes.forEach { classDef ->
val methods = buildList {
classDef.methods.forEach { method ->
// Since the Sequence executes lazily,
// using any() results in only calling
// filterMap until the first index has been found.
if (findPatchIndices(classDef, method)?.any() == true) add(method)
}
}
suspend {
coroutineScope {
classes.map { classDef ->
launch {
val methods = buildList {
coroutineScope {
classDef.methods.map { method ->
launch {
// Since the Sequence executes lazily,
// using any() results in only calling
// filterMap until the first index has been found.
if (findPatchIndices(classDef, method)?.any() == true) add(method)
}
}
}.joinAll()
}

if (methods.isNotEmpty()) {
put(classDef, methods)
if (methods.isNotEmpty()) {
put(classDef, methods)
}
}
}.joinAll()
}
}
}.forEach { (classDef, methods) ->
Expand All @@ -42,7 +55,9 @@ fun <T> transformInstructionsPatch(
val patchIndices = findPatchIndices(mutableClass, mutableMethod)?.toCollection(ArrayDeque())
?: return@methods

while (!patchIndices.isEmpty()) transform(mutableMethod, patchIndices.removeLast())
while (!patchIndices.isEmpty()) {
transform(mutableMethod, patchIndices.removeLast())
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ val deepLinkingPatch = bytecodePatch(
compatibleWith("com.amazon.mShop.android.shopping")

execute {
deepLinkingFingerprint.method.addInstructions(
deepLinkingFingerprint.method().addInstructions(
0,
"""
const/4 v0, 0x1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ val proUnlockPatch = bytecodePatch(
compatibleWith("com.backdrops.wallpapers")

execute {
val registerIndex = proUnlockFingerprint.patternMatch!!.endIndex - 1
val registerIndex = proUnlockFingerprint.patternMatch()!!.endIndex - 1

proUnlockFingerprint.method.apply {
proUnlockFingerprint.method().apply {
val register = getInstruction<OneRegisterInstruction>(registerIndex).registerA
addInstruction(
proUnlockFingerprint.patternMatch!!.endIndex,
proUnlockFingerprint.patternMatch()!!.endIndex,
"const/4 v$register, 0x1",
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@ val removePlayLimitsPatch = bytecodePatch(
compatibleWith("com.bandcamp.android")

execute {
handlePlaybackLimitsFingerprint.method.addInstructions(0, "return-void")
handlePlaybackLimitsFingerprint.method().addInstructions(0, "return-void")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@ val bypassRootChecksPatch = bytecodePatch(
compatibleWith("it.ipzs.cieid")

execute {
checkRootFingerprint.method.addInstruction(1, "return-void")
checkRootFingerprint.method().addInstruction(1, "return-void")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ val disableAdsPatch = bytecodePatch(
// SharedPreferences has a debug boolean value with key "disable_ads", which maps to "DebugCategory.DISABLE_ADS".
//
// MonetizationDebugSettings seems to be the most general setting to work fine.
initializeMonetizationDebugSettingsFingerprint.method.apply {
val insertIndex = initializeMonetizationDebugSettingsFingerprint.patternMatch!!.startIndex
initializeMonetizationDebugSettingsFingerprint.method().apply {
val insertIndex = initializeMonetizationDebugSettingsFingerprint.patternMatch()!!.startIndex
val register = getInstruction<TwoRegisterInstruction>(insertIndex).registerA

addInstructions(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ val enableDebugMenuPatch = bytecodePatch(
compatibleWith("com.duolingo"("5.158.4"))

execute {
initializeBuildConfigProviderFingerprint.method.apply {
val insertIndex = initializeBuildConfigProviderFingerprint.patternMatch!!.startIndex
initializeBuildConfigProviderFingerprint.method().apply {
val insertIndex = initializeBuildConfigProviderFingerprint.patternMatch()!!.startIndex
val register = getInstruction<TwoRegisterInstruction>(insertIndex).registerA

addInstructions(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ val hideSponsoredStoriesPatch = bytecodePatch(
compatibleWith("com.facebook.katana")

execute {
val sponsoredDataModelTemplateMethod = getSponsoredDataModelTemplateFingerprint.originalMethod
val baseModelMapperMethod = baseModelMapperFingerprint.originalMethod
val sponsoredDataModelTemplateMethod = getSponsoredDataModelTemplateFingerprint.originalMethod()
val baseModelMapperMethod = baseModelMapperFingerprint.originalMethod()
val baseModelWithTreeType = baseModelMapperMethod.returnType

val graphQlStoryClassDescriptor = "Lcom/facebook/graphql/model/GraphQLStory;"
Expand All @@ -31,7 +31,7 @@ val hideSponsoredStoriesPatch = bytecodePatch(
// could change in future version, we need to extract them and call the base implementation directly.

val getSponsoredDataHelperMethod = ImmutableMethod(
getStoryVisibilityFingerprint.originalClassDef.type,
getStoryVisibilityFingerprint.originalClassDef().type,
"getSponsoredData",
listOf(ImmutableMethodParameter(graphQlStoryClassDescriptor, null, null)),
baseModelWithTreeType,
Expand Down Expand Up @@ -65,12 +65,12 @@ val hideSponsoredStoriesPatch = bytecodePatch(
)
}

getStoryVisibilityFingerprint.classDef.methods.add(getSponsoredDataHelperMethod)
getStoryVisibilityFingerprint.classDef().methods.add(getSponsoredDataHelperMethod)

// Check if the parameter type is GraphQLStory and if sponsoredDataModelGetter returns a non-null value.
// If so, hide the story by setting the visibility to StoryVisibility.GONE.
getStoryVisibilityFingerprint.method.addInstructionsWithLabels(
getStoryVisibilityFingerprint.patternMatch!!.startIndex,
getStoryVisibilityFingerprint.method().addInstructionsWithLabels(
getStoryVisibilityFingerprint.patternMatch()!!.startIndex,
"""
instance-of v0, p0, $graphQlStoryClassDescriptor
if-eqz v0, :resume_normal
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ val hideStoryAdsPatch = bytecodePatch(
fetchMoreAdsFingerprint,
adsInsertionFingerprint,
).forEach { fingerprint ->
fingerprint.method.replaceInstruction(0, "return-void")
fingerprint.method().replaceInstruction(0, "return-void")
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ val bootloaderDetectionPatch = bytecodePatch(

execute {
setOf(createKeyFingerprint, bootStateFingerprint).forEach { fingerprint ->
fingerprint.method.addInstructions(
fingerprint.method().addInstructions(
0,
"""
const/4 v0, 0x1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ val rootDetectionPatch = bytecodePatch(
compatibleWith("at.gv.bmf.bmf2go")

execute {
rootDetectionFingerprint.method.addInstructions(
rootDetectionFingerprint.method().addInstructions(
0,
"""
sget-object v0, Ljava/lang/Boolean;->FALSE:Ljava/lang/Boolean;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ val enableCustomTabsPatch = bytecodePatch(
compatibleWith("com.google.android.apps.magazines")

execute {
launchCustomTabFingerprint.method.apply {
val checkIndex = launchCustomTabFingerprint.patternMatch!!.endIndex + 1
launchCustomTabFingerprint.method().apply {
val checkIndex = launchCustomTabFingerprint.patternMatch()!!.endIndex + 1
val register = getInstruction<OneRegisterInstruction>(checkIndex).registerA

replaceInstruction(checkIndex, "const/4 v$register, 0x1")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ val spoofFeaturesPatch = bytecodePatch(
@Suppress("NAME_SHADOWING")
val featuresToDisable = featuresToDisable!!.toSet()

initializeFeaturesEnumFingerprint.method.apply {
initializeFeaturesEnumFingerprint.method().apply {
instructions.filter { it.opcode == Opcode.CONST_STRING }.forEach {
val feature = it.getReference<StringReference>()!!.string

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ val restoreHiddenBackUpWhileChargingTogglePatch = bytecodePatch(

execute {
// Patches 'backup_prefs_had_backup_only_when_charging_enabled' to always be true.
val chargingPrefStringIndex = backupPreferencesFingerprint.stringMatches!!.first().index
backupPreferencesFingerprint.method.apply {
val chargingPrefStringIndex = backupPreferencesFingerprint.stringMatches()!!.first().index
backupPreferencesFingerprint.method().apply {
// Get the register of move-result.
val resultRegister = getInstruction<OneRegisterInstruction>(chargingPrefStringIndex + 2).registerA
// Insert const after move-result to override register as true.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ val removeDeviceRestrictionsPatch = bytecodePatch(
compatibleWith("com.google.android.apps.recorder")

execute {
val featureStringIndex = onApplicationCreateFingerprint.stringMatches!!.first().index
val featureStringIndex = onApplicationCreateFingerprint.stringMatches()!!.first().index

onApplicationCreateFingerprint.method.apply {
onApplicationCreateFingerprint.method().apply {
// Remove check for device restrictions.
removeInstructions(featureStringIndex - 2, 5)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ val disableAdsPatch = bytecodePatch(
compatibleWith("com.myprog.hexedit")

execute {
primaryAdsFingerprint.method.replaceInstructions(
primaryAdsFingerprint.method().replaceInstructions(
0,
"""
const/4 v0, 0x1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ val unlockProPatch = bytecodePatch(
compatibleWith("ginlemon.iconpackstudio"("2.2 build 016"))

execute {
checkProFingerprint.method.addInstructions(
checkProFingerprint.method().addInstructions(
0,
"""
const/4 v0, 0x1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,6 @@ val rootDetectionPatch = bytecodePatch(
attestationSupportedCheckFingerprint,
bootloaderCheckFingerprint,
rootCheckFingerprint,
).forEach { it.method.returnEarly(true) }
).forEach { it.method().returnEarly(true) }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ val spoofSignaturePatch = bytecodePatch(
"77ef1be61b2c01ebdabddcbf53cc4b6fd9a3c445606ee77b3758162c80ad8f8137b3c6864e92db904807dcb2be9d7717dd21" +
"bf42c121d620ddfb7914f7a95c713d9e1c1b7bdb4a03d618e40cf7e9e235c0b5687e03b7ab3,publicExponent=10001}"

spoofSignatureFingerprint.method.addInstructions(
spoofSignatureFingerprint.method().addInstructions(
0,
"""
const-string v0, "$expectedSignature"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ val hideAdsPatch = bytecodePatch(
compatibleWith("com.nis.app")

execute {
inshortsAdsFingerprint.method.addInstruction(
inshortsAdsFingerprint.method().addInstruction(
0,
"""
return-void
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ val hideAdsPatch = bytecodePatch(
compatibleWith("com.instagram.android")

execute {
adInjectorFingerprint.method.addInstructions(
adInjectorFingerprint.method().addInstructions(
0,
"""
const/4 v0, 0x0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@ val removeAdsPatch = bytecodePatch(
execute {
// By overwriting the second parameter of the method,
// the view which holds the advertisement is removed.
irplusAdsFingerprint.method.addInstruction(0, "const/4 p2, 0x0")
irplusAdsFingerprint.method().addInstruction(0, "const/4 p2, 0x0")
}
}
Loading
Loading