perf: consumeEvent
Some checks are pending
Build-Apk / build (push) Waiting to run

This commit is contained in:
lisonge 2024-10-01 22:56:51 +08:00
parent 2f666e7164
commit 71af6d340d
2 changed files with 44 additions and 26 deletions

View File

@ -1,13 +1,18 @@
package li.songe.gkd.service
import android.view.accessibility.AccessibilityEvent
import android.view.accessibility.AccessibilityNodeInfo
data class A11yEvent(
val type: Int,
val time: Long,
val appId: String,
val className: String,
)
val event: AccessibilityEvent,
) {
val safeSource: AccessibilityNodeInfo?
get() = event.safeSource
}
fun A11yEvent.sameAs(other: A11yEvent): Boolean {
if (other === this) return true
@ -19,6 +24,7 @@ fun AccessibilityEvent.toA11yEvent(): A11yEvent? {
type = eventType,
time = System.currentTimeMillis(),
appId = packageName?.toString() ?: return null,
className = className?.toString() ?: return null
className = className?.toString() ?: return null,
event = this,
)
}

View File

@ -170,10 +170,10 @@ private fun A11yService.useMatchRule() {
var lastTriggerShizukuTime = 0L
var lastContentEventTime = 0L
val queryEvents = mutableListOf<Pair<AccessibilityEvent, A11yEvent>>()
val queryEvents = mutableListOf<A11yEvent>()
var queryTaskJob: Job?
fun newQueryTask(
byEvent: AccessibilityEvent? = null,
byEvent: A11yEvent? = null,
byForced: Boolean = false,
delayRule: ResolvedRule? = null,
): Job = scope.launchTry(A11yService.queryThread) launchQuery@{
@ -188,7 +188,7 @@ private fun A11yService.useMatchRule() {
}
(if (queryEvents.size > 1) {
val hasDiffItem = queryEvents.any { e ->
queryEvents.any { e2 -> !e.second.sameAs(e2.second) }
queryEvents.any { e2 -> !e.sameAs(e2) }
}
if (hasDiffItem) {// 存在不同的事件节点, 全部丢弃使用 root 查询
if (META.debuggable) {
@ -201,23 +201,23 @@ private fun A11yService.useMatchRule() {
if (META.debuggable) {
Log.d(
"queryEvents",
"保留最后两个事件:${queryEvents.first().second.appId}${queryEvents.map { it.second.className }}"
"保留最后两个事件:${queryEvents.first().appId}${queryEvents.map { it.className }}"
)
}
// type,appId,className 一致, 需要在 synchronized 外验证是否是同一节点
arrayOf(
queryEvents[queryEvents.size - 2].first,
queryEvents.last().first,
queryEvents[queryEvents.size - 2],
queryEvents.last(),
)
}
} else if (queryEvents.size == 1) {
if (META.debuggable) {
Log.d(
"queryEvents",
"只有1个事件:${queryEvents.first().second.appId}${queryEvents.map { it.second.className }}"
"只有1个事件:${queryEvents.first().appId}${queryEvents.map { it.className }}"
)
}
arrayOf(queryEvents.last().first)
arrayOf(queryEvents.last())
} else {
null
}).apply {
@ -359,7 +359,7 @@ private fun A11yService.useMatchRule() {
return lastAppId
}
val t = System.currentTimeMillis()
if (t - lastGetAppIdTime > 30) {// 在 30ms 内使用缓存
if (t - lastGetAppIdTime > 50) {
// 某些应用获取 safeActiveWindow 耗时长, 导致多个事件连续堆积堵塞, 无法检测到 appId 切换导致状态异常
// https://github.com/gkd-kit/gkd/issues/622
lastGetAppIdTime = t
@ -372,19 +372,31 @@ private fun A11yService.useMatchRule() {
return lastAppId
}
val eventDeque = ArrayDeque<A11yEvent>()
fun consumeEvent(
event: AccessibilityEvent, fixedEvent: A11yEvent
headEvent: A11yEvent,
) = scope.launchTry(A11yService.eventThread) launchEvent@{
val evAppId = fixedEvent.appId
val evActivityId = fixedEvent.className
val consumedEvents = synchronized(eventDeque) {
if (eventDeque.firstOrNull() !== headEvent) return@launchEvent
eventDeque.filter { it.sameAs(headEvent) }.apply {
// 如果有多个连续的事件, 全部取出
repeat(size) { eventDeque.removeFirst() }
}
}
if (META.debuggable && consumedEvents.size > 1) {
Log.d("consumeEvent", "合并连续事件:${consumedEvents.size}")
}
val a11yEvent = consumedEvents.last()
val evAppId = a11yEvent.appId
val evActivityId = a11yEvent.className
val oldAppId = topActivityFlow.value.appId
val rightAppId = if (oldAppId == evAppId) {
oldAppId
} else {
getAppIdByCache(fixedEvent) ?: return@launchEvent
getAppIdByCache(a11yEvent) ?: return@launchEvent
}
if (rightAppId == evAppId) {
if (fixedEvent.type == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
if (a11yEvent.type == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
// tv.danmaku.bili, com.miui.home, com.miui.home.launcher.Launcher
if (isActivity(evAppId, evActivityId)) {
updateTopActivity(
@ -394,7 +406,7 @@ private fun A11yService.useMatchRule() {
)
}
} else {
if (storeFlow.value.enableShizukuActivity && fixedEvent.time - lastTriggerShizukuTime > 300) {
if (storeFlow.value.enableShizukuActivity && a11yEvent.time - lastTriggerShizukuTime > 300) {
val shizukuTop = safeGetTopActivity()
if (shizukuTop?.appId == rightAppId) {
if (shizukuTop.activityId == evActivityId) {
@ -406,7 +418,7 @@ private fun A11yService.useMatchRule() {
}
updateTopActivity(shizukuTop)
}
lastTriggerShizukuTime = fixedEvent.time
lastTriggerShizukuTime = a11yEvent.time
}
}
}
@ -425,8 +437,8 @@ private fun A11yService.useMatchRule() {
return@launchEvent
}
synchronized(queryEvents) { queryEvents.add(event to fixedEvent) }
newQueryTask(event)
synchronized(queryEvents) { queryEvents.addAll(consumedEvents) }
newQueryTask(a11yEvent)
}
val skipAppId = "com.android.systemui"
@ -435,12 +447,12 @@ private fun A11yService.useMatchRule() {
return@onA11yEvent
}
// AccessibilityEvent 的 clear 方法会在后续时间被 某些系统 调用导致内部数据丢失, 导致异步子线程获取到的数据不一致
val fixedEvent = event.toA11yEvent() ?: return@onA11yEvent
if (fixedEvent.type == AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED) {
if (fixedEvent.time - lastContentEventTime < 100 && fixedEvent.time - appChangeTime > 5000 && fixedEvent.time - lastTriggerTime > 3000) {
val a11yEvent = event.toA11yEvent() ?: return@onA11yEvent
if (a11yEvent.type == AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED) {
if (a11yEvent.time - lastContentEventTime < 100 && a11yEvent.time - appChangeTime > 5000 && a11yEvent.time - lastTriggerTime > 3000) {
return@onA11yEvent
}
lastContentEventTime = fixedEvent.time
lastContentEventTime = a11yEvent.time
}
if (META.debuggable) {
Log.d(
@ -448,8 +460,8 @@ private fun A11yService.useMatchRule() {
"type:${event.eventType},app:${event.packageName},cls:${event.className}"
)
}
// eventDeque.addLast(event to fixedEvent)
consumeEvent(event, fixedEvent)
synchronized(eventDeque) { eventDeque.add(a11yEvent) }
consumeEvent(a11yEvent)
}
}