Performance Optimization
In DexKit, various queries may achieve the same functionality, but the difference in performance can be significant, varying by several tens of times. This section will introduce some techniques for performance optimization.
At the native layer, DexKit maintains lists of classes, methods, and fields in the Dex file. How does DexKit scan these lists in several APIs? The traversal order of findClass
, findMethod
, and findField
is based on the respective lists' sequential order. Then, each condition is matched one by one.
declaredClass condition is too heavy
Some users may use the declaredClass
condition to write queries like the following when using:
private fun badCode(bridge: DexKitBridge) {
bridge.findMethod {
matcher {
declaredClass {
usingStrings("getUid", "", "_event")
}
modifiers = Modifier.PUBLIC or Modifier.STATIC
returnType = "long"
addInvoke {
name = "parseLong"
}
addInvoke {
name = "toString"
}
}
}.single().let {
println(it)
}
}
This search takes 4310ms
.
At first glance, this query seems fine, but in reality, its performance is very poor. Why? As mentioned earlier, the findMethod
API traverses all methods and then matches each condition one by one. However, there is a many-to-one relationship between methods and classes, meaning a class may contain multiple methods, but a method can only belong to one class. Therefore, during the process of traversing all methods, each method will be matched once with the declaredClass
condition, leading to performance waste.
So, let's change our approach. By first searching for declaredClass
and then using chain calls, we can search for methods within the classes that meet the criteria. Won't this help avoid the issue?
private fun goodCode(bridge: DexKitBridge) {
bridge.findClass {
matcher {
usingStrings("getUid", "", "_event")
}
}.findMethod {
matcher {
modifiers = Modifier.PUBLIC or Modifier.STATIC
returnType = "long"
addInvoke {
name = "parseLong"
}
addInvoke {
name = "toString"
}
}
}.single().let {
println(it)
}
}
This search takes 77ms
, showing a performance improvement by several tens of times.
When using findMethod
or findField
, the declaredClass
condition should be avoided as much as possible.