From 933fd91d0894a35891a46ac3a226837e2f900ac2 Mon Sep 17 00:00:00 2001 From: weishu Date: Fri, 22 Dec 2023 12:30:33 +0800 Subject: [PATCH 1/8] =?UTF-8?q?perf:=20=E7=BC=93=E5=AD=98=20activity=20?= =?UTF-8?q?=E4=BF=A1=E6=81=AF=EF=BC=8C=E9=81=BF=E5=85=8D=E9=87=8D=E5=A4=8D?= =?UTF-8?q?=E6=9F=A5=E8=AF=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../li/songe/gkd/service/GkdAbService.kt | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/app/src/main/kotlin/li/songe/gkd/service/GkdAbService.kt b/app/src/main/kotlin/li/songe/gkd/service/GkdAbService.kt index 5318f761e..618885903 100644 --- a/app/src/main/kotlin/li/songe/gkd/service/GkdAbService.kt +++ b/app/src/main/kotlin/li/songe/gkd/service/GkdAbService.kt @@ -9,6 +9,7 @@ import android.content.pm.PackageManager import android.graphics.Bitmap import android.graphics.PixelFormat import android.os.Build +import android.util.LruCache import android.view.Display import android.view.View import android.view.WindowManager @@ -98,20 +99,25 @@ class GkdAbService : CompositionAbService({ return TopActivity(appId = top.packageName, activityId = top.className) } + val activityCache = object : LruCache, Boolean>(128) { + override fun create(key: Pair): Boolean { + return kotlin.runCatching { + packageManager.getActivityInfo( + ComponentName( + key.first, key.second + ), 0 + ) + }.getOrNull() != null + } + } + fun isActivity( appId: String, activityId: String, ): Boolean { - if (appId == topActivityFlow.value.appId && activityId == topActivityFlow.value.activityId) return true - val r = (try { - packageManager.getActivityInfo( - ComponentName( - appId, activityId - ), 0 - ) - } catch (e: PackageManager.NameNotFoundException) { - null - } != null) + if (appId == topActivityFlow.value.appId && activityId == topActivityFlow.value?.activityId) return true + val cacheKey = Pair(appId, activityId) + val r = activityCache.get(cacheKey) return r } From 5e8e610efa22c36cc86ebbc3f072976dad920a0c Mon Sep 17 00:00:00 2001 From: weishu Date: Wed, 27 Dec 2023 11:59:03 +0800 Subject: [PATCH 2/8] =?UTF-8?q?perf:=20=E4=BD=BF=E7=94=A8=E7=BA=BF?= =?UTF-8?q?=E7=A8=8B=E6=B1=A0=E8=80=8C=E9=9D=9E=E5=8D=8F=E7=A8=8B=E5=A4=84?= =?UTF-8?q?=E7=90=86=20IO=20=E4=BA=8B=E4=BB=B6=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 在 pixel6 测试,协程启动耗时约 0.5-1ms,线程池约 0.02-0.1ms。 --- app/src/main/kotlin/li/songe/gkd/service/GkdAbService.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/src/main/kotlin/li/songe/gkd/service/GkdAbService.kt b/app/src/main/kotlin/li/songe/gkd/service/GkdAbService.kt index 618885903..07c227aac 100644 --- a/app/src/main/kotlin/li/songe/gkd/service/GkdAbService.kt +++ b/app/src/main/kotlin/li/songe/gkd/service/GkdAbService.kt @@ -57,6 +57,7 @@ import li.songe.gkd.util.subsItemsFlow import li.songe.gkd.util.updateStorage import li.songe.gkd.util.updateSubscription import li.songe.selector.Selector +import java.util.concurrent.Executors import kotlin.coroutines.resume import kotlin.coroutines.suspendCoroutine @@ -124,7 +125,7 @@ class GkdAbService : CompositionAbService({ var lastTriggerShizukuTime = 0L var lastContentEventTime = 0L val queryThread = Dispatchers.IO.limitedParallelism(1) - val eventThread = Dispatchers.IO.limitedParallelism(1) + val eventExecutor = Executors.newSingleThreadExecutor() onDestroy { queryThread.cancel() } @@ -207,7 +208,7 @@ class GkdAbService : CompositionAbService({ val evActivityId = fixedEvent.className - scope.launch(eventThread) { + eventExecutor.execute launch@{ val eventNode = event.source ?: return@launch val oldAppId = topActivityFlow.value.appId val rightAppId = if (oldAppId == evAppId) { From b0131ecd5be8ad5ce176558386ac3a1634cdc6c4 Mon Sep 17 00:00:00 2001 From: lisonge Date: Wed, 27 Dec 2023 12:11:31 +0800 Subject: [PATCH 3/8] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E8=AE=A2?= =?UTF-8?q?=E9=98=85=E6=A0=A1=E9=AA=8C=E9=94=99=E8=AF=AF=E6=8F=90=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/kotlin/li/songe/gkd/data/RawSubscription.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/kotlin/li/songe/gkd/data/RawSubscription.kt b/app/src/main/kotlin/li/songe/gkd/data/RawSubscription.kt index 1665a488e..b66aaf29d 100644 --- a/app/src/main/kotlin/li/songe/gkd/data/RawSubscription.kt +++ b/app/src/main/kotlin/li/songe/gkd/data/RawSubscription.kt @@ -570,11 +570,11 @@ data class RawSubscription( } subscription.apps.forEach { a -> a.groups.findDuplicatedItem { v -> v.key }?.let { v -> - error("duplicated app group: key=${v.key}") + error("duplicated app group: key=${v.key}, appId=${a.id}") } a.groups.forEach { g -> g.rules.findDuplicatedItem { v -> v.key }?.let { v -> - error("duplicated app rule: key=${v.key}, groupKey=${g.key}, appId=${a.id} ") + error("duplicated app rule: key=${v.key}, groupKey=${g.key}, appId=${a.id}") } } } From 3dfefa2a7d57728120bf0de3c82f25860a3ffb44 Mon Sep 17 00:00:00 2001 From: lisonge Date: Wed, 27 Dec 2023 12:19:39 +0800 Subject: [PATCH 4/8] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=20shizuku=20?= =?UTF-8?q?=E8=BF=90=E8=A1=8C=E9=80=BB=E8=BE=91=20(#423)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/kotlin/li/songe/gkd/service/GkdAbService.kt | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/app/src/main/kotlin/li/songe/gkd/service/GkdAbService.kt b/app/src/main/kotlin/li/songe/gkd/service/GkdAbService.kt index 5318f761e..228de788a 100644 --- a/app/src/main/kotlin/li/songe/gkd/service/GkdAbService.kt +++ b/app/src/main/kotlin/li/songe/gkd/service/GkdAbService.kt @@ -75,7 +75,7 @@ class GkdAbService : CompositionAbService({ val shizukuGrantFlow = MutableStateFlow(false) var lastCheckShizukuTime = 0L onAccessibilityEvent { // 借助无障碍轮询校验 shizuku 权限 - if (storeFlow.value.enableService && it.eventType == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {// 筛选降低判断频率 + if (storeFlow.value.enableShizuku && it.eventType == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {// 筛选降低判断频率 val t = System.currentTimeMillis() if (t - lastCheckShizukuTime > 5000L) { lastCheckShizukuTime = t @@ -93,6 +93,7 @@ class GkdAbService : CompositionAbService({ // 当锁屏/上拉通知栏时, safeActiveWindow 没有 activityId, 但是此时 shizuku 获取到是前台 app 的 appId 和 activityId fun getShizukuTopActivity(): TopActivity? { + if (!storeFlow.value.enableShizuku) return null // 平均耗时 5 ms val top = safeGetTasksFc()?.lastOrNull()?.topActivity ?: return null return TopActivity(appId = top.packageName, activityId = top.className) @@ -218,7 +219,7 @@ class GkdAbService : CompositionAbService({ ) } } else { - if (fixedEvent.time - lastTriggerShizukuTime > 300) { + if (storeFlow.value.enableShizuku && fixedEvent.time - lastTriggerShizukuTime > 300) { val shizukuTop = getShizukuTopActivity() if (shizukuTop != null && shizukuTop.appId == rightAppId) { if (shizukuTop.activityId == evActivityId) { @@ -297,12 +298,12 @@ class GkdAbService : CompositionAbService({ } var lastUpdateSubsTime = 0L - onAccessibilityEvent { + onAccessibilityEvent {// 借助 无障碍事件 触发自动检测更新 if (it.eventType == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {// 筛选降低判断频率 - // 借助 无障碍事件 触发自动检测更新 val i = storeFlow.value.updateSubsInterval + if (i <= 0) return@onAccessibilityEvent val t = System.currentTimeMillis() - if (i > 0 && t - lastUpdateSubsTime > i.coerceAtLeast(60 * 60_000)) { + if (t - lastUpdateSubsTime > i.coerceAtLeast(60 * 60_000)) { lastUpdateSubsTime = t checkSubsUpdate() } From 6116dd981bd51e2111ac496ea7a4ace8be631ce3 Mon Sep 17 00:00:00 2001 From: lisonge Date: Wed, 27 Dec 2023 12:31:17 +0800 Subject: [PATCH 5/8] chore: format code --- app/src/main/kotlin/li/songe/gkd/service/GkdAbService.kt | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/app/src/main/kotlin/li/songe/gkd/service/GkdAbService.kt b/app/src/main/kotlin/li/songe/gkd/service/GkdAbService.kt index 57ee59c44..20cc30fed 100644 --- a/app/src/main/kotlin/li/songe/gkd/service/GkdAbService.kt +++ b/app/src/main/kotlin/li/songe/gkd/service/GkdAbService.kt @@ -5,7 +5,6 @@ import android.content.ComponentName import android.content.Context import android.content.Intent import android.content.IntentFilter -import android.content.pm.PackageManager import android.graphics.Bitmap import android.graphics.PixelFormat import android.os.Build @@ -117,10 +116,9 @@ class GkdAbService : CompositionAbService({ appId: String, activityId: String, ): Boolean { - if (appId == topActivityFlow.value.appId && activityId == topActivityFlow.value?.activityId) return true + if (appId == topActivityFlow.value.appId && activityId == topActivityFlow.value.activityId) return true val cacheKey = Pair(appId, activityId) - val r = activityCache.get(cacheKey) - return r + return activityCache.get(cacheKey) } var lastTriggerShizukuTime = 0L From 032ce0fcc6ae5ba7c574e3ab15b2b59d3910f67b Mon Sep 17 00:00:00 2001 From: lisonge Date: Wed, 27 Dec 2023 12:38:11 +0800 Subject: [PATCH 6/8] =?UTF-8?q?fix:=20=E5=AD=90=E5=AD=99=E8=8A=82=E7=82=B9?= =?UTF-8?q?=E9=81=8D=E5=8E=86=E9=A1=BA=E5=BA=8F=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/kotlin/li/songe/gkd/service/AbExt.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/kotlin/li/songe/gkd/service/AbExt.kt b/app/src/main/kotlin/li/songe/gkd/service/AbExt.kt index a7dd5bc4c..30ef5091b 100644 --- a/app/src/main/kotlin/li/songe/gkd/service/AbExt.kt +++ b/app/src/main/kotlin/li/songe/gkd/service/AbExt.kt @@ -170,6 +170,7 @@ val abTransform = Transform( sequence { val stack = getChildren(node).toMutableList() if (stack.isEmpty()) return@sequence + stack.reverse() val tempNodes = mutableListOf() do { val top = stack.removeLast() From 6af00a44bcc1093a04d01aa6cac4cc561f16ce6c Mon Sep 17 00:00:00 2001 From: lisonge Date: Wed, 27 Dec 2023 22:21:22 +0800 Subject: [PATCH 7/8] =?UTF-8?q?fix:=20=E6=95=B0=E6=8D=AE=E5=BA=93=E7=82=B9?= =?UTF-8?q?=E5=87=BB=E8=AE=B0=E5=BD=95=E6=8F=92=E5=85=A5=E5=86=B2=E7=AA=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/li/songe/gkd/service/AbState.kt | 39 +++++++++++-------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/app/src/main/kotlin/li/songe/gkd/service/AbState.kt b/app/src/main/kotlin/li/songe/gkd/service/AbState.kt index 9aadd45fd..10eda147f 100644 --- a/app/src/main/kotlin/li/songe/gkd/service/AbState.kt +++ b/app/src/main/kotlin/li/songe/gkd/service/AbState.kt @@ -2,6 +2,8 @@ package li.songe.gkd.service import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock import li.songe.gkd.appScope import li.songe.gkd.data.AppRule import li.songe.gkd.data.ClickLog @@ -102,25 +104,28 @@ var lastTriggerRule: ResolvedRule? = null var lastTriggerTime = 0L var appChangeTime = 0L +val clickLogMutex = Mutex() fun insertClickLog(rule: ResolvedRule) { appScope.launchTry(Dispatchers.IO) { - val clickLog = ClickLog( - appId = topActivityFlow.value.appId, - activityId = topActivityFlow.value.activityId, - subsId = rule.subsItem.id, - subsVersion = rule.rawSubs.version, - groupKey = rule.group.key, - groupType = when (rule) { - is AppRule -> SubsConfig.AppGroupType - is GlobalRule -> SubsConfig.GlobalGroupType - }, - ruleIndex = rule.index, - ruleKey = rule.key, - ) - DbSet.clickLogDao.insert(clickLog) - increaseClickCount() - if (recordStoreFlow.value.clickCount % 100 == 0) { - DbSet.clickLogDao.deleteKeepLatest() + clickLogMutex.withLock { + increaseClickCount() + val clickLog = ClickLog( + appId = topActivityFlow.value.appId, + activityId = topActivityFlow.value.activityId, + subsId = rule.subsItem.id, + subsVersion = rule.rawSubs.version, + groupKey = rule.group.key, + groupType = when (rule) { + is AppRule -> SubsConfig.AppGroupType + is GlobalRule -> SubsConfig.GlobalGroupType + }, + ruleIndex = rule.index, + ruleKey = rule.key, + ) + DbSet.clickLogDao.insert(clickLog) + if (recordStoreFlow.value.clickCount % 100 == 0) { + DbSet.clickLogDao.deleteKeepLatest() + } } } } From ad442052ea109664b3240a3d34f647c9d29677a1 Mon Sep 17 00:00:00 2001 From: lisonge Date: Wed, 27 Dec 2023 22:33:59 +0800 Subject: [PATCH 8/8] fix: failed get event.source (#426) --- app/src/main/kotlin/li/songe/gkd/service/GkdAbService.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/src/main/kotlin/li/songe/gkd/service/GkdAbService.kt b/app/src/main/kotlin/li/songe/gkd/service/GkdAbService.kt index 20cc30fed..a79237aef 100644 --- a/app/src/main/kotlin/li/songe/gkd/service/GkdAbService.kt +++ b/app/src/main/kotlin/li/songe/gkd/service/GkdAbService.kt @@ -208,7 +208,11 @@ class GkdAbService : CompositionAbService({ eventExecutor.execute launch@{ - val eventNode = event.source ?: return@launch + val eventNode = if (event.className == null) { + null // https://github.com/gkd-kit/gkd/issues/426 event.clear 已被系统调用 + } else { + event.source + } val oldAppId = topActivityFlow.value.appId val rightAppId = if (oldAppId == evAppId) { oldAppId