mirror of
https://github.com/gkd-kit/gkd.git
synced 2024-11-16 11:42:22 +08:00
This commit is contained in:
parent
2a16b33275
commit
274f0e7f29
|
@ -1,8 +1,10 @@
|
|||
package li.songe.gkd.data
|
||||
|
||||
import android.accessibilityservice.AccessibilityService
|
||||
import android.util.Log
|
||||
import android.view.accessibility.AccessibilityNodeInfo
|
||||
import kotlinx.coroutines.Job
|
||||
import li.songe.gkd.BuildConfig
|
||||
import li.songe.gkd.service.GkdAbService
|
||||
import li.songe.gkd.service.createCacheTransform
|
||||
import li.songe.gkd.service.createNoCacheTransform
|
||||
|
@ -133,13 +135,17 @@ sealed class ResolvedRule(
|
|||
else -> true
|
||||
}
|
||||
|
||||
private val useCache = (matches + excludeMatches).any { s -> s.useCache }
|
||||
private val useCache = (matches + excludeMatches + anyMatches).any { s -> s.useCache }
|
||||
private val transform = if (useCache) defaultCacheTransform else defaultTransform
|
||||
|
||||
fun query(
|
||||
node: AccessibilityNodeInfo?,
|
||||
isRootNode: Boolean,
|
||||
): AccessibilityNodeInfo? {
|
||||
val t = System.currentTimeMillis()
|
||||
if (t - lastCacheTime > MIN_CACHE_INTERVAL) {
|
||||
clearNodeCache(t)
|
||||
}
|
||||
val nodeInfo = if (matchRoot) {
|
||||
val rootNode = (if (isRootNode) {
|
||||
node
|
||||
|
@ -147,46 +153,41 @@ sealed class ResolvedRule(
|
|||
GkdAbService.service?.safeActiveWindow
|
||||
}) ?: return null
|
||||
rootNode.apply {
|
||||
transform.cache.parentMap[this] = null
|
||||
transform.cache.rootNode = this
|
||||
}
|
||||
} else {
|
||||
node
|
||||
}
|
||||
try {
|
||||
if (nodeInfo == null) return null
|
||||
var target: AccessibilityNodeInfo? = null
|
||||
if (anyMatches.isNotEmpty()) {
|
||||
for (selector in anyMatches) {
|
||||
target = nodeInfo.querySelector(
|
||||
selector,
|
||||
quickFind,
|
||||
transform.transform,
|
||||
isRootNode || matchRoot
|
||||
) ?: break
|
||||
}
|
||||
if (target == null) return null
|
||||
}
|
||||
for (selector in matches) {
|
||||
if (nodeInfo == null) return null
|
||||
var target: AccessibilityNodeInfo? = null
|
||||
if (anyMatches.isNotEmpty()) {
|
||||
for (selector in anyMatches) {
|
||||
target = nodeInfo.querySelector(
|
||||
selector,
|
||||
quickFind,
|
||||
transform.transform,
|
||||
isRootNode || matchRoot
|
||||
) ?: return null
|
||||
) ?: break
|
||||
}
|
||||
for (selector in excludeMatches) {
|
||||
nodeInfo.querySelector(
|
||||
selector,
|
||||
quickFind,
|
||||
transform.transform,
|
||||
isRootNode || matchRoot
|
||||
)?.let { return null }
|
||||
}
|
||||
return target
|
||||
} finally {
|
||||
defaultTransform.cache.clear()
|
||||
defaultCacheTransform.cache.clear()
|
||||
if (target == null) return null
|
||||
}
|
||||
for (selector in matches) {
|
||||
target = nodeInfo.querySelector(
|
||||
selector,
|
||||
quickFind,
|
||||
transform.transform,
|
||||
isRootNode || matchRoot
|
||||
) ?: return null
|
||||
}
|
||||
for (selector in excludeMatches) {
|
||||
nodeInfo.querySelector(
|
||||
selector,
|
||||
quickFind,
|
||||
transform.transform,
|
||||
isRootNode || matchRoot
|
||||
)?.let { return null }
|
||||
}
|
||||
return target
|
||||
}
|
||||
|
||||
private val performer = ActionPerformer.getAction(
|
||||
|
@ -275,5 +276,15 @@ fun getFixActivityIds(
|
|||
|
||||
private val defaultTransform by lazy { createNoCacheTransform() }
|
||||
private val defaultCacheTransform by lazy { createCacheTransform() }
|
||||
private var lastCacheTime = 0L
|
||||
private const val MIN_CACHE_INTERVAL = 2000L
|
||||
|
||||
|
||||
fun clearNodeCache(t: Long = System.currentTimeMillis()) {
|
||||
lastCacheTime = t
|
||||
if (BuildConfig.DEBUG) {
|
||||
val sizeList = defaultCacheTransform.cache.sizeList
|
||||
Log.d("cache", "clear cache, sizeList=$sizeList")
|
||||
}
|
||||
defaultTransform.cache.clear()
|
||||
defaultCacheTransform.cache.clear()
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package li.songe.gkd.service
|
|||
|
||||
import android.accessibilityservice.AccessibilityService
|
||||
import android.graphics.Rect
|
||||
import android.util.LruCache
|
||||
import android.view.accessibility.AccessibilityEvent
|
||||
import android.view.accessibility.AccessibilityNodeInfo
|
||||
import com.blankj.utilcode.util.LogUtils
|
||||
|
@ -108,6 +109,7 @@ fun AccessibilityNodeInfo.querySelector(
|
|||
|
||||
|
||||
// https://github.com/gkd-kit/gkd/issues/115
|
||||
// https://github.com/gkd-kit/gkd/issues/650
|
||||
// 限制节点遍历的数量避免内存溢出
|
||||
private const val MAX_CHILD_SIZE = 512
|
||||
private const val MAX_DESCENDANTS_SIZE = 4096
|
||||
|
@ -209,17 +211,30 @@ data class CacheTransform(
|
|||
val cache: NodeCache,
|
||||
)
|
||||
|
||||
data class NodeCache(
|
||||
val childMap: MutableMap<Pair<AccessibilityNodeInfo, Int>, AccessibilityNodeInfo> = HashMap(),
|
||||
val indexMap: MutableMap<AccessibilityNodeInfo, Int> = HashMap(),
|
||||
val parentMap: MutableMap<AccessibilityNodeInfo, AccessibilityNodeInfo?> = HashMap(),
|
||||
) {
|
||||
|
||||
private operator fun <K, V> LruCache<K, V>.set(child: K, value: V): V {
|
||||
return put(child, value)
|
||||
}
|
||||
|
||||
private const val MAX_CACHE_SIZE = MAX_DESCENDANTS_SIZE
|
||||
|
||||
class NodeCache {
|
||||
private val childMap =
|
||||
LruCache<Pair<AccessibilityNodeInfo, Int>, AccessibilityNodeInfo>(MAX_CACHE_SIZE)
|
||||
val indexMap = LruCache<AccessibilityNodeInfo, Int>(MAX_CACHE_SIZE)
|
||||
private val parentMap = LruCache<AccessibilityNodeInfo, AccessibilityNodeInfo>(MAX_CACHE_SIZE)
|
||||
var rootNode: AccessibilityNodeInfo? = null
|
||||
|
||||
fun clear() {
|
||||
childMap.clear()
|
||||
parentMap.clear()
|
||||
indexMap.clear()
|
||||
rootNode = null
|
||||
childMap.evictAll()
|
||||
parentMap.evictAll()
|
||||
indexMap.evictAll()
|
||||
}
|
||||
|
||||
val sizeList: List<Int>
|
||||
get() = listOf(childMap.size(), parentMap.size(), indexMap.size())
|
||||
|
||||
fun getIndex(node: AccessibilityNodeInfo): Int {
|
||||
indexMap[node]?.let { return it }
|
||||
getParent(node)?.forEachIndexed { index, child ->
|
||||
|
@ -234,14 +249,19 @@ data class NodeCache(
|
|||
}
|
||||
|
||||
fun getParent(node: AccessibilityNodeInfo): AccessibilityNodeInfo? {
|
||||
if (rootNode == node) {
|
||||
return null
|
||||
}
|
||||
val parent = parentMap[node]
|
||||
if (parent != null) {
|
||||
return parent
|
||||
} else if (parentMap.contains(node)) {
|
||||
return null
|
||||
}
|
||||
return node.parent.apply {
|
||||
parentMap[node] = this
|
||||
if (this != null) {
|
||||
parentMap[node] = this
|
||||
} else {
|
||||
rootNode = node
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -41,6 +41,7 @@ import li.songe.gkd.data.AttrInfo
|
|||
import li.songe.gkd.data.GkdAction
|
||||
import li.songe.gkd.data.RpcError
|
||||
import li.songe.gkd.data.RuleStatus
|
||||
import li.songe.gkd.data.clearNodeCache
|
||||
import li.songe.gkd.debug.SnapshotExt
|
||||
import li.songe.gkd.shizuku.getShizukuCanUsedFlow
|
||||
import li.songe.gkd.shizuku.shizukuIsSafeOK
|
||||
|
@ -173,6 +174,10 @@ class GkdAbService : CompositionAbService({
|
|||
pair
|
||||
}
|
||||
val activityRule = getAndUpdateCurrentRules()
|
||||
if (activityRule.currentRules.isEmpty()) {
|
||||
return@launchTry
|
||||
}
|
||||
clearNodeCache()
|
||||
for (rule in (activityRule.currentRules)) { // 规则数量有可能过多导致耗时过长
|
||||
val statusCode = rule.status
|
||||
if (statusCode == RuleStatus.Status3 && rule.matchDelayJob == null) {
|
||||
|
|
Loading…
Reference in New Issue
Block a user