diff --git a/src/main/kotlin/app/revanced/patches/youtube/player/ambientmode/AmbientModeSwitchPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/player/ambientmode/AmbientModeSwitchPatch.kt index fad1abaa6..3c01f99fd 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/player/ambientmode/AmbientModeSwitchPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/player/ambientmode/AmbientModeSwitchPatch.kt @@ -3,16 +3,24 @@ package app.revanced.patches.youtube.player.ambientmode import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.InstructionExtensions.addInstructions import app.revanced.patcher.extensions.InstructionExtensions.getInstruction +import app.revanced.patcher.patch.PatchException import app.revanced.patches.youtube.player.ambientmode.fingerprints.AmbientModeInFullscreenFingerprint -import app.revanced.patches.youtube.player.ambientmode.fingerprints.PowerSaveModeFingerprint +import app.revanced.patches.youtube.player.ambientmode.fingerprints.PowerSaveModeBroadcastReceiverFingerprint +import app.revanced.patches.youtube.player.ambientmode.fingerprints.PowerSaveModeSyntheticFingerprint import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE import app.revanced.patches.youtube.utils.integrations.Constants.PLAYER_CLASS_DESCRIPTOR import app.revanced.patches.youtube.utils.settings.SettingsPatch -import app.revanced.util.getTargetIndexWithMethodReferenceNameReversed +import app.revanced.util.getStringInstructionIndex +import app.revanced.util.getTargetIndex +import app.revanced.util.getTargetIndexReversed import app.revanced.util.literalInstructionBooleanHook import app.revanced.util.patch.BaseBytecodePatch import app.revanced.util.resultOrThrow +import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction +import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction +import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction35c +import com.android.tools.smali.dexlib2.iface.reference.MethodReference @Suppress("unused") object AmbientModeSwitchPatch : BaseBytecodePatch( @@ -22,22 +30,44 @@ object AmbientModeSwitchPatch : BaseBytecodePatch( compatiblePackages = COMPATIBLE_PACKAGE, fingerprints = setOf( AmbientModeInFullscreenFingerprint, - PowerSaveModeFingerprint + PowerSaveModeBroadcastReceiverFingerprint, + PowerSaveModeSyntheticFingerprint ) ) { + private var syntheticClassList = emptyArray() + override fun execute(context: BytecodeContext) { // region patch for bypass ambient mode restrictions - PowerSaveModeFingerprint.resultOrThrow().let { - it.mutableMethod.apply { - val powerSaveModePrimaryIndex = getTargetIndexWithMethodReferenceNameReversed("isPowerSaveMode") - val powerSaveModeSecondaryIndex = getTargetIndexWithMethodReferenceNameReversed(powerSaveModePrimaryIndex - 1, "isPowerSaveMode") + mapOf( + PowerSaveModeBroadcastReceiverFingerprint to false, + PowerSaveModeSyntheticFingerprint to true + ).forEach { (fingerprint, reversed) -> + fingerprint.resultOrThrow().mutableMethod.apply { + val stringIndex = getStringInstructionIndex("android.os.action.POWER_SAVE_MODE_CHANGED") + val targetIndex = + if (reversed) + getTargetIndexReversed(stringIndex, Opcode.INVOKE_DIRECT) + else + getTargetIndex(stringIndex, Opcode.INVOKE_DIRECT) + val targetClass = (getInstruction(targetIndex).reference as MethodReference).definingClass + + syntheticClassList += targetClass + } + } + + syntheticClassList.distinct().forEach { className -> + context.findClass(className)?.mutableClass?.methods?.first { method -> + method.name == "accept" + }?.apply { + for ((index, instruction) in implementation!!.instructions.withIndex()) { + if (instruction.opcode != Opcode.INVOKE_VIRTUAL) + continue + + if (((instruction as Instruction35c).reference as MethodReference).name != "isPowerSaveMode") + continue - arrayOf( - powerSaveModePrimaryIndex, - powerSaveModeSecondaryIndex - ).forEach { index -> val register = getInstruction(index + 1).registerA addInstructions( @@ -47,7 +77,7 @@ object AmbientModeSwitchPatch : BaseBytecodePatch( """ ) } - } + } ?: throw PatchException("Could not find $className") } // endregion diff --git a/src/main/kotlin/app/revanced/patches/youtube/player/ambientmode/fingerprints/PowerSaveModeBroadcastReceiverFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/player/ambientmode/fingerprints/PowerSaveModeBroadcastReceiverFingerprint.kt new file mode 100644 index 000000000..3dac07051 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/player/ambientmode/fingerprints/PowerSaveModeBroadcastReceiverFingerprint.kt @@ -0,0 +1,18 @@ +package app.revanced.patches.youtube.player.ambientmode.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.MethodFingerprint +import com.android.tools.smali.dexlib2.AccessFlags + +internal object PowerSaveModeBroadcastReceiverFingerprint : MethodFingerprint( + returnType = "V", + accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, + parameters = listOf("Landroid/content/Context;", "Landroid/content/Intent;"), + strings = listOf("android.os.action.POWER_SAVE_MODE_CHANGED"), + // There are two classes that inherit [BroadcastReceiver]. + // Check the method count to find the correct class. + customFingerprint = { _, classDef -> + classDef.superclass == "Landroid/content/BroadcastReceiver;" + && classDef.methods.count() == 2 + } +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/player/ambientmode/fingerprints/PowerSaveModeFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/player/ambientmode/fingerprints/PowerSaveModeFingerprint.kt deleted file mode 100644 index 23f91268e..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/player/ambientmode/fingerprints/PowerSaveModeFingerprint.kt +++ /dev/null @@ -1,36 +0,0 @@ -package app.revanced.patches.youtube.player.ambientmode.fingerprints - -import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.MethodFingerprint -import com.android.tools.smali.dexlib2.AccessFlags -import com.android.tools.smali.dexlib2.Opcode -import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction35c -import com.android.tools.smali.dexlib2.iface.reference.MethodReference - -internal object PowerSaveModeFingerprint : MethodFingerprint( - returnType = "V", - accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, - parameters = listOf("Ljava/lang/Object;"), - customFingerprint = custom@{ methodDef, _ -> - if (methodDef.name != "accept") - return@custom false - - val instructions = methodDef.implementation?.instructions!! - - if (instructions.count() < 20) - return@custom false - - var count = 0 - for (instruction in instructions) { - if (instruction.opcode != Opcode.INVOKE_VIRTUAL) - continue - - val invokeInstruction = instruction as Instruction35c - if ((invokeInstruction.reference as MethodReference).name != "isPowerSaveMode") - continue - - count++ - } - count == 2 - } -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/player/ambientmode/fingerprints/PowerSaveModeSyntheticFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/player/ambientmode/fingerprints/PowerSaveModeSyntheticFingerprint.kt new file mode 100644 index 000000000..41ade92e7 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/player/ambientmode/fingerprints/PowerSaveModeSyntheticFingerprint.kt @@ -0,0 +1,12 @@ +package app.revanced.patches.youtube.player.ambientmode.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.MethodFingerprint +import com.android.tools.smali.dexlib2.AccessFlags + +internal object PowerSaveModeSyntheticFingerprint : MethodFingerprint( + returnType = "V", + accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, + parameters = listOf("Ljava/lang/Object;"), + strings = listOf("android.os.action.POWER_SAVE_MODE_CHANGED") +) \ No newline at end of file