fix(YouTube): Ambient mode control patch does not work on YouTube 19.05.36

This commit is contained in:
inotia00 2024-05-10 01:32:00 +09:00
parent 7990031a18
commit 455e92c5ea
4 changed files with 72 additions and 48 deletions

View File

@ -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<String>()
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<ReferenceInstruction>(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<OneRegisterInstruction>(index + 1).registerA
addInstructions(
@ -47,7 +77,7 @@ object AmbientModeSwitchPatch : BaseBytecodePatch(
"""
)
}
}
} ?: throw PatchException("Could not find $className")
}
// endregion

View File

@ -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
}
)

View File

@ -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
}
)

View File

@ -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")
)