more or less finish composite api

This commit is contained in:
oSumAtrIX
2026-01-06 04:06:37 +01:00
parent 18570656cc
commit d2461f92aa
7 changed files with 1727 additions and 286 deletions

View File

@@ -5,7 +5,6 @@ android-compileSdk = "36"
android-minSdk = "26" android-minSdk = "26"
kotlin = "2.3.0" kotlin = "2.3.0"
apktool-lib = "2.10.1.1" apktool-lib = "2.10.1.1"
kotlinx-coroutines-core = "1.10.2"
mockk = "1.14.7" mockk = "1.14.7"
multidexlib2 = "3.0.3.r3" multidexlib2 = "3.0.3.r3"
# Tracking https://github.com/google/smali/issues/64. # Tracking https://github.com/google/smali/issues/64.
@@ -17,7 +16,6 @@ vanniktechMavenPublish = "0.35.0"
[libraries] [libraries]
apktool-lib = { module = "app.revanced:apktool-lib", version.ref = "apktool-lib" } apktool-lib = { module = "app.revanced:apktool-lib", version.ref = "apktool-lib" }
kotlin-reflect = { module = "org.jetbrains.kotlin:kotlin-reflect", version.ref = "kotlin" } kotlin-reflect = { module = "org.jetbrains.kotlin:kotlin-reflect", version.ref = "kotlin" }
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx-coroutines-core" }
kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" } kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" }
mockk = { module = "io.mockk:mockk", version.ref = "mockk" } mockk = { module = "io.mockk:mockk", version.ref = "mockk" }
multidexlib2 = { module = "app.revanced:multidexlib2", version.ref = "multidexlib2" } multidexlib2 = { module = "app.revanced:multidexlib2", version.ref = "multidexlib2" }

View File

@@ -41,7 +41,6 @@ kotlin {
commonMain.dependencies { commonMain.dependencies {
implementation(libs.apktool.lib) implementation(libs.apktool.lib)
implementation(libs.kotlin.reflect) implementation(libs.kotlin.reflect)
implementation(libs.kotlinx.coroutines.core)
implementation(libs.multidexlib2) implementation(libs.multidexlib2)
implementation(libs.smali) implementation(libs.smali)
implementation(libs.xpp3) implementation(libs.xpp3)

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,5 @@
package app.revanced.patcher.extensions package app.revanced.patcher.extensions
import com.android.tools.smali.dexlib2.mutable.MutableMethod
import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.builder.BuilderInstruction import com.android.tools.smali.dexlib2.builder.BuilderInstruction
import com.android.tools.smali.dexlib2.builder.BuilderOffsetInstruction import com.android.tools.smali.dexlib2.builder.BuilderOffsetInstruction
@@ -10,6 +9,7 @@ import com.android.tools.smali.dexlib2.builder.instruction.*
import com.android.tools.smali.dexlib2.iface.Method import com.android.tools.smali.dexlib2.iface.Method
import com.android.tools.smali.dexlib2.iface.MethodImplementation import com.android.tools.smali.dexlib2.iface.MethodImplementation
import com.android.tools.smali.dexlib2.iface.instruction.Instruction import com.android.tools.smali.dexlib2.iface.instruction.Instruction
import com.android.tools.smali.dexlib2.mutable.MutableMethod
fun Method.accessFlags(vararg flags: AccessFlags) = fun Method.accessFlags(vararg flags: AccessFlags) =
accessFlags.and(flags.map { it.ordinal }.reduce { acc, i -> acc or i }) != 0 accessFlags.and(flags.map { it.ordinal }.reduce { acc, i -> acc or i }) != 0

View File

@@ -2,14 +2,13 @@ package app.revanced.patcher.patch
import app.revanced.patcher.PatchesResult import app.revanced.patcher.PatchesResult
import app.revanced.patcher.extensions.instructionsOrNull import app.revanced.patcher.extensions.instructionsOrNull
import app.revanced.patcher.extensions.string
import app.revanced.patcher.util.ClassMerger.merge import app.revanced.patcher.util.ClassMerger.merge
import app.revanced.patcher.util.MethodNavigator import app.revanced.patcher.util.MethodNavigator
import com.android.tools.smali.dexlib2.iface.ClassDef import com.android.tools.smali.dexlib2.iface.ClassDef
import com.android.tools.smali.dexlib2.iface.DexFile import com.android.tools.smali.dexlib2.iface.DexFile
import com.android.tools.smali.dexlib2.iface.Method import com.android.tools.smali.dexlib2.iface.Method
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
import com.android.tools.smali.dexlib2.iface.reference.MethodReference import com.android.tools.smali.dexlib2.iface.reference.MethodReference
import com.android.tools.smali.dexlib2.iface.reference.StringReference
import com.android.tools.smali.dexlib2.mutable.MutableClassDef import com.android.tools.smali.dexlib2.mutable.MutableClassDef
import com.android.tools.smali.dexlib2.mutable.MutableClassDef.Companion.toMutable import com.android.tools.smali.dexlib2.mutable.MutableClassDef.Companion.toMutable
import lanchon.multidexlib2.BasicDexFileNamer import lanchon.multidexlib2.BasicDexFileNamer
@@ -141,13 +140,8 @@ class BytecodePatchContext internal constructor(
private fun ClassDef.forEachString(action: (Method, String) -> Unit) { private fun ClassDef.forEachString(action: (Method, String) -> Unit) {
methods.asSequence().forEach { method -> methods.asSequence().forEach { method ->
method.instructionsOrNull?.asSequence() method.instructionsOrNull?.asSequence()
?.filterIsInstance<ReferenceInstruction>() ?.mapNotNull { it.string }
?.map { it.reference } ?.forEach { string -> action(method, string) }
?.filterIsInstance<StringReference>()
?.map { it.string }
?.forEach { string ->
action(method, string)
}
} }
} }

View File

@@ -1,8 +1,11 @@
package app.revanced.patcher package app.revanced.patcher
import app.revanced.patcher.BytecodePatchContextMethodMatching.firstMethod
import app.revanced.patcher.BytecodePatchContextMethodMatching.firstMethodDeclarativelyOrNull
import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.patch.bytecodePatch
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
import com.android.tools.smali.dexlib2.immutable.ImmutableClassDef
import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.BeforeAll import org.junit.jupiter.api.BeforeAll
import org.junit.jupiter.api.TestInstance import org.junit.jupiter.api.TestInstance
@@ -13,13 +16,13 @@ import kotlin.test.assertFalse
import kotlin.test.assertNotNull import kotlin.test.assertNotNull
@TestInstance(TestInstance.Lifecycle.PER_CLASS) @TestInstance(TestInstance.Lifecycle.PER_CLASS)
object MatchingTest : PatcherTestBase() { class MatchingTest : PatcherTestBase() {
@BeforeAll @BeforeAll
fun setup() = setupMock() fun setup() = setupMock()
@Test @Test
fun `finds via builder api`() { fun `finds via builder api`() {
fun firstMethodBuilder(fail: Boolean = false) = firstMethodBuilder { fun firstMethodComposite(fail: Boolean = false) = firstMethodComposite {
name("method") name("method")
definingClass("class") definingClass("class")
@@ -36,19 +39,20 @@ object MatchingTest : PatcherTestBase() {
) )
} }
bytecodePatch { with(bytecodePatchContext) {
apply { assertNotNull(firstMethodComposite().methodOrNull) { "Expected to find a method" }
assertNotNull(firstMethodBuilder().methodOrNull) { "Expected to find a method" } Assertions.assertNull(firstMethodComposite(fail = true).immutableMethodOrNull) { "Expected to not find a method" }
Assertions.assertNull(firstMethodBuilder(fail = true).methodOrNull) { "Expected to not find a method" } Assertions.assertNotNull(
} firstMethodComposite().match(classDefs.first()).methodOrNull
}() ) { "Expected to find a method matching in a specific class" }
}
} }
@Test @Test
fun `finds via declarative api`() { fun `finds via declarative api`() {
bytecodePatch { bytecodePatch {
apply { apply {
val method = firstMethodByDeclarativePredicateOrNull { val method = firstMethodDeclarativelyOrNull {
anyOf { anyOf {
predicate { name == "method" } predicate { name == "method" }
add { false } add { false }
@@ -78,7 +82,7 @@ object MatchingTest : PatcherTestBase() {
val matcher = indexedMatcher<Int>() val matcher = indexedMatcher<Int>()
matcher.apply { matcher.apply {
+head { this > 5 } +head<Int> { this > 5 }
} }
assertFalse( assertFalse(
matcher(iterable), matcher(iterable),
@@ -86,7 +90,7 @@ object MatchingTest : PatcherTestBase() {
) )
matcher.clear() matcher.clear()
matcher.apply { +head { this == 1 } }(iterable) matcher.apply { +head<Int> { this == 1 } }(iterable)
assertEquals( assertEquals(
listOf(0), listOf(0),
matcher.indices, matcher.indices,
@@ -107,7 +111,7 @@ object MatchingTest : PatcherTestBase() {
matcher.clear() matcher.clear()
matcher.apply { matcher.apply {
+head { this == 1 } +head<Int> { this == 1 }
add { _, _ -> this == 2 } add { _, _ -> this == 2 }
add { _, _ -> this == 4 } add { _, _ -> this == 4 }
}(iterable) }(iterable)
@@ -147,7 +151,7 @@ object MatchingTest : PatcherTestBase() {
matcher.clear() matcher.clear()
matcher.apply { matcher.apply {
+head { this == 1 } +head<Int> { this == 1 }
+after(2..5) { this == 4 } +after(2..5) { this == 4 }
add { _, _ -> this == 8 } add { _, _ -> this == 8 }
add { _, _ -> this == 9 } add { _, _ -> this == 9 }