mirror of
https://github.com/revanced/revanced-patches
synced 2025-01-26 02:27:33 +01:00
perf(general-ads): hook pathBuilder
This commit is contained in:
parent
6f5b20858f
commit
e864c6eef9
@ -1,12 +1,8 @@
|
|||||||
package app.revanced.patches.youtube.ad.general.bytecode.extensions
|
package app.revanced.patches.youtube.ad.general.bytecode.extensions
|
||||||
|
|
||||||
import app.revanced.patcher.extensions.addInstructions
|
|
||||||
import app.revanced.patcher.extensions.softCompareTo
|
import app.revanced.patcher.extensions.softCompareTo
|
||||||
import app.revanced.patcher.patch.PatchResultError
|
import app.revanced.patcher.patch.PatchResultError
|
||||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableClass
|
import app.revanced.patcher.util.proxy.mutableTypes.MutableClass
|
||||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
|
||||||
import org.jf.dexlib2.builder.BuilderInstruction
|
|
||||||
import org.jf.dexlib2.builder.MutableMethodImplementation
|
|
||||||
import org.jf.dexlib2.iface.Method
|
import org.jf.dexlib2.iface.Method
|
||||||
import org.jf.dexlib2.iface.instruction.Instruction
|
import org.jf.dexlib2.iface.instruction.Instruction
|
||||||
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
|
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
|
||||||
@ -16,21 +12,6 @@ import org.jf.dexlib2.iface.reference.Reference
|
|||||||
import org.jf.dexlib2.immutable.reference.ImmutableMethodReference
|
import org.jf.dexlib2.immutable.reference.ImmutableMethodReference
|
||||||
|
|
||||||
internal object MethodExtensions {
|
internal object MethodExtensions {
|
||||||
internal fun MutableMethodImplementation.insertBlocks(
|
|
||||||
startIndex: Int,
|
|
||||||
vararg blocks: List<BuilderInstruction>,
|
|
||||||
) {
|
|
||||||
blocks.reversed().forEach {
|
|
||||||
this.addInstructions(
|
|
||||||
startIndex, it
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun MutableClass.addMethod(mutableMethod: MutableMethod) {
|
|
||||||
this.methods.add(mutableMethod)
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun MutableClass.findMutableMethodOf(
|
internal fun MutableClass.findMutableMethodOf(
|
||||||
method: Method
|
method: Method
|
||||||
) = this.methods.first {
|
) = this.methods.first {
|
||||||
|
@ -6,6 +6,9 @@ import app.revanced.patcher.annotation.Name
|
|||||||
import app.revanced.patcher.annotation.Version
|
import app.revanced.patcher.annotation.Version
|
||||||
import app.revanced.patcher.data.impl.BytecodeData
|
import app.revanced.patcher.data.impl.BytecodeData
|
||||||
import app.revanced.patcher.extensions.addInstructions
|
import app.revanced.patcher.extensions.addInstructions
|
||||||
|
import app.revanced.patcher.extensions.instruction
|
||||||
|
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||||
|
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve
|
||||||
import app.revanced.patcher.patch.PatchResult
|
import app.revanced.patcher.patch.PatchResult
|
||||||
import app.revanced.patcher.patch.PatchResultError
|
import app.revanced.patcher.patch.PatchResultError
|
||||||
import app.revanced.patcher.patch.PatchResultSuccess
|
import app.revanced.patcher.patch.PatchResultSuccess
|
||||||
@ -14,23 +17,18 @@ import app.revanced.patcher.patch.annotations.Patch
|
|||||||
import app.revanced.patcher.patch.impl.BytecodePatch
|
import app.revanced.patcher.patch.impl.BytecodePatch
|
||||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableClass
|
import app.revanced.patcher.util.proxy.mutableTypes.MutableClass
|
||||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||||
import app.revanced.patcher.util.smali.toInstructions
|
import app.revanced.patcher.util.smali.ExternalLabel
|
||||||
import app.revanced.patches.youtube.ad.general.annotation.GeneralAdsCompatibility
|
import app.revanced.patches.youtube.ad.general.annotation.GeneralAdsCompatibility
|
||||||
import app.revanced.patches.youtube.ad.general.bytecode.extensions.MethodExtensions.addMethod
|
|
||||||
import app.revanced.patches.youtube.ad.general.bytecode.extensions.MethodExtensions.findMutableMethodOf
|
import app.revanced.patches.youtube.ad.general.bytecode.extensions.MethodExtensions.findMutableMethodOf
|
||||||
import app.revanced.patches.youtube.ad.general.bytecode.extensions.MethodExtensions.insertBlocks
|
|
||||||
import app.revanced.patches.youtube.ad.general.bytecode.extensions.MethodExtensions.toDescriptor
|
import app.revanced.patches.youtube.ad.general.bytecode.extensions.MethodExtensions.toDescriptor
|
||||||
import app.revanced.patches.youtube.ad.general.bytecode.utils.MethodUtils.createMutableMethod
|
|
||||||
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
|
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
|
||||||
import app.revanced.patches.youtube.misc.mapping.patch.ResourceMappingResourcePatch
|
import app.revanced.patches.youtube.misc.mapping.patch.ResourceMappingResourcePatch
|
||||||
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
|
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
|
||||||
import app.revanced.patches.youtube.misc.settings.framework.components.impl.StringResource
|
import app.revanced.patches.youtube.misc.settings.framework.components.impl.StringResource
|
||||||
import app.revanced.patches.youtube.misc.settings.framework.components.impl.SwitchPreference
|
import app.revanced.patches.youtube.misc.settings.framework.components.impl.SwitchPreference
|
||||||
import org.jf.dexlib2.Opcode
|
import org.jf.dexlib2.Opcode
|
||||||
import org.jf.dexlib2.builder.MutableMethodImplementation
|
import org.jf.dexlib2.builder.instruction.BuilderInstruction10x
|
||||||
import org.jf.dexlib2.builder.instruction.*
|
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
|
||||||
import org.jf.dexlib2.iface.MethodImplementation
|
|
||||||
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
|
|
||||||
import org.jf.dexlib2.iface.instruction.formats.Instruction21c
|
import org.jf.dexlib2.iface.instruction.formats.Instruction21c
|
||||||
import org.jf.dexlib2.iface.instruction.formats.Instruction22c
|
import org.jf.dexlib2.iface.instruction.formats.Instruction22c
|
||||||
import org.jf.dexlib2.iface.instruction.formats.Instruction31i
|
import org.jf.dexlib2.iface.instruction.formats.Instruction31i
|
||||||
@ -38,7 +36,6 @@ import org.jf.dexlib2.iface.instruction.formats.Instruction35c
|
|||||||
import org.jf.dexlib2.iface.reference.FieldReference
|
import org.jf.dexlib2.iface.reference.FieldReference
|
||||||
import org.jf.dexlib2.iface.reference.MethodReference
|
import org.jf.dexlib2.iface.reference.MethodReference
|
||||||
import org.jf.dexlib2.iface.reference.StringReference
|
import org.jf.dexlib2.iface.reference.StringReference
|
||||||
import org.jf.dexlib2.immutable.reference.ImmutableMethodReference
|
|
||||||
|
|
||||||
@Patch
|
@Patch
|
||||||
@DependsOn([ResourceMappingResourcePatch::class, IntegrationsPatch::class, SettingsPatch::class])
|
@DependsOn([ResourceMappingResourcePatch::class, IntegrationsPatch::class, SettingsPatch::class])
|
||||||
@ -170,13 +167,6 @@ class GeneralBytecodeAdsPatch : BytecodePatch() {
|
|||||||
StringResource("revanced_adremover_paid_content_enabled_summary_on", "Paid content is hidden"),
|
StringResource("revanced_adremover_paid_content_enabled_summary_on", "Paid content is hidden"),
|
||||||
StringResource("revanced_adremover_paid_content_enabled_summary_off", "Paid content is shown")
|
StringResource("revanced_adremover_paid_content_enabled_summary_off", "Paid content is shown")
|
||||||
),
|
),
|
||||||
SwitchPreference(
|
|
||||||
"revanced_adremover_suggested",
|
|
||||||
StringResource("revanced_adremover_suggested_enabled_title", "Remove personal suggestions"),
|
|
||||||
true,
|
|
||||||
StringResource("revanced_adremover_suggested_enabled_summary_on", "Personal suggestions are hidden"),
|
|
||||||
StringResource("revanced_adremover_suggested_enabled_summary_off", "Personal suggestions are shown")
|
|
||||||
),
|
|
||||||
SwitchPreference(
|
SwitchPreference(
|
||||||
"revanced_adremover_hide_suggestions",
|
"revanced_adremover_hide_suggestions",
|
||||||
StringResource("revanced_adremover_hide_suggestions_enabled_title", "Hide suggestions"),
|
StringResource("revanced_adremover_hide_suggestions_enabled_title", "Hide suggestions"),
|
||||||
@ -329,72 +319,54 @@ class GeneralBytecodeAdsPatch : BytecodePatch() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
stringReferences[2] -> { // Litho ads
|
stringReferences[2] -> { // Litho ads
|
||||||
// create proxied method.
|
|
||||||
val proxy = data.proxy(classDef)
|
val proxy = data.proxy(classDef)
|
||||||
val proxiedClass = proxy.resolve()
|
val proxiedClass = proxy.resolve()
|
||||||
|
|
||||||
// add getIsEmpty method
|
|
||||||
proxiedClass.addGetIsEmptyMethod()
|
|
||||||
|
|
||||||
// get required method to patch and get references from
|
|
||||||
val lithoMethod = getLithoMethod(proxiedClass)
|
val lithoMethod = getLithoMethod(proxiedClass)
|
||||||
?: return PatchResultError("Could not find required litho method to patch.")
|
?: return PatchResultError("Could not find required Litho method to patch.")
|
||||||
val lithoMethodImplementation = lithoMethod.implementation!!
|
|
||||||
|
|
||||||
// create and add getTemplateName method
|
val instructionWithNeededDescriptor =
|
||||||
val getTemplateMethod =
|
lithoMethod.implementation!!.instructions.indexOfFirst {
|
||||||
proxiedClass.createGetTemplateNameMethod(lithoMethodImplementation)
|
|
||||||
proxiedClass.addMethod(getTemplateMethod)
|
|
||||||
|
|
||||||
val lithoInstructions = lithoMethodImplementation.instructions
|
|
||||||
val thisType = proxiedClass.type
|
|
||||||
val templateNameParameterType = getTemplateMethod.parameterTypes.first()
|
|
||||||
|
|
||||||
// get reference descriptors
|
|
||||||
val indexOfReference1 = lithoInstructions.indexOfFirst {
|
|
||||||
it.opcode == Opcode.INVOKE_STATIC_RANGE
|
it.opcode == Opcode.INVOKE_STATIC_RANGE
|
||||||
}
|
}
|
||||||
val descriptor1 =
|
|
||||||
lithoInstructions.elementAt(indexOfReference1).toDescriptor<MethodReference>()
|
// get required descriptors
|
||||||
val descriptor2 = lithoInstructions.elementAt(indexOfReference1 + 2)
|
val createEmptyComponentDescriptor =
|
||||||
|
lithoMethod.instruction(instructionWithNeededDescriptor)
|
||||||
|
.toDescriptor<MethodReference>()
|
||||||
|
val emptyComponentFieldDescriptor =
|
||||||
|
lithoMethod.instruction(instructionWithNeededDescriptor + 2)
|
||||||
.toDescriptor<FieldReference>()
|
.toDescriptor<FieldReference>()
|
||||||
|
|
||||||
// create label
|
val pathBuilderAnchorFingerprint = object : MethodFingerprint(
|
||||||
val lithoRemoveLabel = lithoMethodImplementation.newLabelForIndex(0)
|
opcodes = listOf(
|
||||||
|
Opcode.CONST_16,
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.IPUT_OBJECT
|
||||||
|
)
|
||||||
|
) {}
|
||||||
|
|
||||||
// create branch instructions
|
val pathBuilderScanResult = pathBuilderAnchorFingerprint.also {
|
||||||
val ifEqzFirstInstruction =
|
it.resolve(data, lithoMethod, classDef)
|
||||||
BuilderInstruction21t(Opcode.IF_EQZ, 0, lithoRemoveLabel)
|
}.result!!.scanResult.patternScanResult!!
|
||||||
val ifEqzSecondInstruction =
|
|
||||||
BuilderInstruction21t(Opcode.IF_EQZ, 1, lithoRemoveLabel)
|
|
||||||
|
|
||||||
// create blocks
|
val clobberedRegister =
|
||||||
val block1 = """
|
(lithoMethod.instruction(pathBuilderScanResult.startIndex) as OneRegisterInstruction).registerA
|
||||||
invoke-static/range {p3}, $thisType->getTemplateName($templateNameParameterType)Ljava/lang/String;
|
|
||||||
move-result-object v0
|
val insertIndex = pathBuilderScanResult.endIndex + 1
|
||||||
""".toInstructions(lithoMethod)
|
lithoMethod.addInstructions(
|
||||||
val block2 = """
|
insertIndex, // right after setting the component.pathBuilder field,
|
||||||
move-object/from16 v1, p3
|
"""
|
||||||
iget-object v2, v1, $templateNameParameterType->b:Ljava/nio/ByteBuffer;
|
invoke-static {v5}, Lapp/revanced/integrations/patches/GeneralBytecodeAdsPatch;->isAdComponent(Ljava/lang/StringBuilder;)Z
|
||||||
invoke-static {v0, v2}, Lapp/revanced/integrations/patches/GeneralBytecodeAdsPatch;->containsAd(Ljava/lang/String;Ljava/nio/ByteBuffer;)Z
|
move-result v$clobberedRegister
|
||||||
move-result v1
|
if-eqz v$clobberedRegister, :not_an_ad
|
||||||
""".toInstructions(lithoMethod)
|
|
||||||
val block3 = """
|
|
||||||
move-object/from16 v2, p1
|
move-object/from16 v2, p1
|
||||||
invoke-static {v2}, $descriptor1
|
invoke-static {v2}, $createEmptyComponentDescriptor
|
||||||
move-result-object v0
|
move-result-object v0
|
||||||
iget-object v0, v0, $descriptor2
|
iget-object v0, v0, $emptyComponentFieldDescriptor
|
||||||
return-object v0
|
return-object v0
|
||||||
""".toInstructions(lithoMethod)
|
""",
|
||||||
|
listOf(ExternalLabel("not_an_ad", lithoMethod.instruction(insertIndex)))
|
||||||
// insert blocks and branch instructions
|
|
||||||
lithoMethodImplementation.insertBlocks(
|
|
||||||
0,
|
|
||||||
block1,
|
|
||||||
listOf(ifEqzFirstInstruction),
|
|
||||||
block2,
|
|
||||||
listOf(ifEqzSecondInstruction),
|
|
||||||
block3,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -414,142 +386,4 @@ class GeneralBytecodeAdsPatch : BytecodePatch() {
|
|||||||
instruction.opcode == Opcode.CONST && (instruction as Instruction31i).narrowLiteral == lithoConstant
|
instruction.opcode == Opcode.CONST && (instruction as Instruction31i).narrowLiteral == lithoConstant
|
||||||
} ?: false
|
} ?: false
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun MutableClass.addGetIsEmptyMethod() {
|
|
||||||
val getIsEmptyImplementation = MutableMethodImplementation(1)
|
|
||||||
|
|
||||||
// create target instructions
|
|
||||||
val firstTargetInstruction = BuilderInstruction11n(Opcode.CONST_4, 0, 1)
|
|
||||||
val secondTargetInstruction = BuilderInstruction11n(Opcode.CONST_4, 0, 0)
|
|
||||||
|
|
||||||
// add instructions to the instruction list
|
|
||||||
getIsEmptyImplementation.addInstructions(
|
|
||||||
0, listOf(
|
|
||||||
// BuilderInstruction21t(Opcode.IF_EQZ, 0, first),
|
|
||||||
BuilderInstruction35c(
|
|
||||||
Opcode.INVOKE_VIRTUAL,
|
|
||||||
1,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
ImmutableMethodReference("Ljava/lang/String;", "isEmpty", null, "Z")
|
|
||||||
),
|
|
||||||
BuilderInstruction11x(Opcode.MOVE_RESULT, 0),
|
|
||||||
// BuilderInstruction21t(Opcode.IF_EQZ, 0, second),
|
|
||||||
// BuilderInstruction10t(Opcode.GOTO, first),
|
|
||||||
secondTargetInstruction,
|
|
||||||
BuilderInstruction11x(Opcode.RETURN, 0),
|
|
||||||
firstTargetInstruction,
|
|
||||||
BuilderInstruction11x(Opcode.RETURN, 0),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
val getIsEmptyInstructions = getIsEmptyImplementation.instructions
|
|
||||||
|
|
||||||
// create labels for the target instructions
|
|
||||||
val firstLabel =
|
|
||||||
getIsEmptyImplementation.newLabelForIndex(getIsEmptyInstructions.indexOf(firstTargetInstruction))
|
|
||||||
val secondLabel =
|
|
||||||
getIsEmptyImplementation.newLabelForIndex(getIsEmptyInstructions.indexOf(secondTargetInstruction))
|
|
||||||
|
|
||||||
// create branch instructions to the labels
|
|
||||||
val ifEqzFirstInstruction = BuilderInstruction21t(Opcode.IF_EQZ, 0, firstLabel)
|
|
||||||
val ifEqzSecondInstruction = BuilderInstruction21t(Opcode.IF_EQZ, 0, secondLabel)
|
|
||||||
val gotoInstruction = BuilderInstruction10t(Opcode.GOTO, firstLabel)
|
|
||||||
|
|
||||||
// insert remaining branch instructions, order of adding those instructions is important
|
|
||||||
getIsEmptyImplementation.addInstructions(
|
|
||||||
2, listOf(
|
|
||||||
ifEqzSecondInstruction, gotoInstruction
|
|
||||||
)
|
|
||||||
)
|
|
||||||
getIsEmptyImplementation.addInstruction(
|
|
||||||
0, ifEqzFirstInstruction
|
|
||||||
)
|
|
||||||
|
|
||||||
this.addMethod(
|
|
||||||
createMutableMethod(
|
|
||||||
this.type, "getIsEmpty", "Z", "Ljava/lang/String;", getIsEmptyImplementation
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun MutableClass.createGetTemplateNameMethod(lithoMethodImplementation: MethodImplementation): MutableMethod {
|
|
||||||
var counter = 1
|
|
||||||
val descriptors = buildList {
|
|
||||||
for (instruction in lithoMethodImplementation.instructions) {
|
|
||||||
if (instruction !is ReferenceInstruction) continue
|
|
||||||
if (counter++ > 4) break
|
|
||||||
|
|
||||||
add(instruction.toDescriptor<MethodReference>())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val getTemplateNameImplementation = MutableMethodImplementation(2)
|
|
||||||
|
|
||||||
// create code blocks
|
|
||||||
val block1 = """
|
|
||||||
invoke-virtual {p0}, ${descriptors[0]}
|
|
||||||
move-result-object p0
|
|
||||||
const v0, $lithoConstant
|
|
||||||
invoke-static {p0, v0}, ${descriptors[1]}
|
|
||||||
move-result-object p0
|
|
||||||
""".toInstructions()
|
|
||||||
val block2 = """
|
|
||||||
invoke-static {p0}, ${descriptors[2]}
|
|
||||||
move-result-object p0
|
|
||||||
invoke-virtual {p0}, ${descriptors[3]}
|
|
||||||
move-result-object v0
|
|
||||||
invoke-static {v0}, ${this.type}->getIsEmpty(Ljava/lang/String;)Z
|
|
||||||
move-result v0
|
|
||||||
""".toInstructions()
|
|
||||||
val block3 = """
|
|
||||||
invoke-virtual {p0}, ${descriptors[3]}
|
|
||||||
move-result-object p0
|
|
||||||
return-object p0
|
|
||||||
""".toInstructions()
|
|
||||||
|
|
||||||
// create target instruction
|
|
||||||
val targetInstruction = BuilderInstruction11n(Opcode.CONST_4, 1, 0)
|
|
||||||
// and remaining instruction
|
|
||||||
val returnInstruction = BuilderInstruction11x(Opcode.RETURN_OBJECT, 1)
|
|
||||||
|
|
||||||
// insert blocks and instructions
|
|
||||||
getTemplateNameImplementation.insertBlocks(
|
|
||||||
0,
|
|
||||||
block1,
|
|
||||||
block2,
|
|
||||||
block3,
|
|
||||||
listOf(
|
|
||||||
targetInstruction, returnInstruction
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
// create label for target instruction
|
|
||||||
val targetInstructionLabel =
|
|
||||||
getTemplateNameImplementation.newLabelForIndex(getTemplateNameImplementation.instructions.size - 2)
|
|
||||||
|
|
||||||
// create branch instructions to the label
|
|
||||||
val ifEqzInstruction = BuilderInstruction21t(Opcode.IF_EQZ, 1, targetInstructionLabel)
|
|
||||||
val ifNezInstruction = BuilderInstruction21t(Opcode.IF_NEZ, 0, targetInstructionLabel)
|
|
||||||
|
|
||||||
// insert branch instructions
|
|
||||||
getTemplateNameImplementation.addInstruction(
|
|
||||||
block1.size, ifEqzInstruction
|
|
||||||
)
|
|
||||||
getTemplateNameImplementation.addInstruction(
|
|
||||||
block1.size + block2.size + 1, ifNezInstruction
|
|
||||||
)
|
|
||||||
|
|
||||||
// create the method
|
|
||||||
return createMutableMethod(
|
|
||||||
this.type,
|
|
||||||
"getTemplateName",
|
|
||||||
"Ljava/lang/String;",
|
|
||||||
descriptors[0].split("->")[0], // a bit weird to get the type this way,
|
|
||||||
getTemplateNameImplementation
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user