perf: log lifecycle

This commit is contained in:
lisonge 2024-10-21 00:04:41 +08:00
parent dc54864751
commit 724ff77c97
9 changed files with 181 additions and 102 deletions

View File

@ -10,6 +10,7 @@ import kotlinx.coroutines.launch
import li.songe.gkd.util.OnChangeListen
import li.songe.gkd.util.OnDestroy
import li.songe.gkd.util.OnTileClick
import li.songe.gkd.util.useLogLifecycle
class FloatingTileService : TileService(), OnDestroy, OnChangeListen, OnTileClick {
override fun onStartListening() {
@ -41,6 +42,7 @@ class FloatingTileService : TileService(), OnDestroy, OnChangeListen, OnTileClic
}
init {
useLogLifecycle()
scope.launch {
combine(
FloatingService.isRunning,

View File

@ -45,6 +45,8 @@ import li.songe.gkd.notif.notifyService
import li.songe.gkd.permission.notificationState
import li.songe.gkd.service.A11yService
import li.songe.gkd.util.LOCAL_HTTP_SUBS_ID
import li.songe.gkd.util.OnCreate
import li.songe.gkd.util.OnDestroy
import li.songe.gkd.util.SERVER_SCRIPT_URL
import li.songe.gkd.util.getIpAddressInLocalNetwork
import li.songe.gkd.util.keepNullJson
@ -54,20 +56,45 @@ import li.songe.gkd.util.storeFlow
import li.songe.gkd.util.subsItemsFlow
import li.songe.gkd.util.toast
import li.songe.gkd.util.updateSubscription
import li.songe.gkd.util.useAliveFlow
import li.songe.gkd.util.useLogLifecycle
import java.io.File
class HttpService : Service() {
private val scope = MainScope()
class HttpService : Service(), OnCreate, OnDestroy {
override fun onBind(intent: Intent?) = null
override fun onCreate() {
super.onCreate()
onCreated()
}
override fun onDestroy() {
super.onDestroy()
onDestroyed()
}
val scope = MainScope().apply { onDestroyed { cancel() } }
private val httpServerPortFlow = storeFlow.map(scope) { s -> s.httpServerPort }
private var server: EmbeddedServer<CIOApplicationEngine, CIOApplicationEngine.Configuration>? =
null
override fun onCreate() {
super.onCreate()
isRunning.value = true
localNetworkIpsFlow.value = getIpAddressInLocalNetwork()
init {
useLogLifecycle()
useAliveFlow(isRunning)
onCreated { localNetworkIpsFlow.value = getIpAddressInLocalNetwork() }
onDestroyed { localNetworkIpsFlow.value = emptyList() }
onDestroyed {
if (storeFlow.value.autoClearMemorySubs) {
deleteSubscription(LOCAL_HTTP_SUBS_ID)
}
}
onCreated {
scope.launchTry(Dispatchers.IO) {
httpServerPortFlow.collect { port ->
server?.stop()
@ -86,15 +113,6 @@ class HttpService : Service() {
}
}
}
override fun onDestroy() {
super.onDestroy()
scope.cancel()
isRunning.value = false
localNetworkIpsFlow.value = emptyList()
if (storeFlow.value.autoClearMemorySubs) {
deleteSubscription(LOCAL_HTTP_SUBS_ID)
}
}
companion object {
@ -109,8 +127,6 @@ class HttpService : Service() {
app.startForegroundService(Intent(app, HttpService::class.java))
}
}
override fun onBind(intent: Intent?) = null
}
@Serializable

View File

@ -10,6 +10,7 @@ import kotlinx.coroutines.launch
import li.songe.gkd.util.OnChangeListen
import li.songe.gkd.util.OnDestroy
import li.songe.gkd.util.OnTileClick
import li.songe.gkd.util.useLogLifecycle
class HttpTileService : TileService(), OnDestroy, OnChangeListen, OnTileClick {
override fun onStartListening() {
@ -41,6 +42,7 @@ class HttpTileService : TileService(), OnDestroy, OnChangeListen, OnTileClick {
}
init {
useLogLifecycle()
scope.launch {
combine(
HttpService.isRunning,

View File

@ -1,26 +1,29 @@
package li.songe.gkd.debug
import android.annotation.SuppressLint
import android.app.Service
import android.content.Context
import android.content.Intent
import com.blankj.utilcode.util.LogUtils
import kotlinx.coroutines.flow.MutableStateFlow
import li.songe.gkd.app
import li.songe.gkd.notif.notifyService
import li.songe.gkd.notif.screenshotNotif
import li.songe.gkd.util.OnCreate
import li.songe.gkd.util.OnDestroy
import li.songe.gkd.util.ScreenshotUtil
import li.songe.gkd.util.componentName
import li.songe.gkd.util.useAliveFlow
import li.songe.gkd.util.useLogLifecycle
import java.lang.ref.WeakReference
class ScreenshotService : Service() {
class ScreenshotService : Service(), OnCreate, OnDestroy {
override fun onBind(intent: Intent?) = null
override fun onCreate() {
super.onCreate()
isRunning.value = true
screenshotNotif.notifyService(this)
onCreated()
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
try {
return super.onStartCommand(intent, flags, startId)
@ -35,25 +38,31 @@ class ScreenshotService : Service() {
override fun onDestroy() {
super.onDestroy()
isRunning.value = false
screenshotUtil?.destroy()
screenshotUtil = null
onDestroyed()
}
private var screenshotUtil: ScreenshotUtil? = null
init {
useLogLifecycle()
useAliveFlow(isRunning)
onCreated { screenshotNotif.notifyService(this) }
onCreated { instance = WeakReference(this) }
onDestroyed { instance = WeakReference(null) }
onDestroyed { screenshotUtil?.destroy() }
}
companion object {
suspend fun screenshot() = screenshotUtil?.execute()
@SuppressLint("StaticFieldLeak")
private var screenshotUtil: ScreenshotUtil? = null
fun start(context: Context = app, intent: Intent) {
intent.component = ScreenshotService::class.componentName
context.startForegroundService(intent)
}
private var instance = WeakReference<ScreenshotService>(null)
val isRunning = MutableStateFlow(false)
fun stop(context: Context = app) {
context.stopService(Intent(context, ScreenshotService::class.java))
suspend fun screenshot() = instance.get()?.screenshotUtil?.execute()
fun start(intent: Intent) {
intent.component = ScreenshotService::class.componentName
app.startForegroundService(intent)
}
fun stop() {
app.stopService(Intent(app, ScreenshotService::class.java))
}
}
}

View File

@ -56,6 +56,7 @@ import li.songe.gkd.util.map
import li.songe.gkd.util.showActionToast
import li.songe.gkd.util.storeFlow
import li.songe.gkd.util.toast
import li.songe.gkd.util.useLogLifecycle
import li.songe.selector.MatchOption
import li.songe.selector.Selector
import java.lang.ref.WeakReference
@ -89,6 +90,7 @@ class A11yService : AccessibilityService(), OnCreate, OnA11yConnected, OnA11yEve
val scope = CoroutineScope(Dispatchers.Default).apply { onDestroyed { cancel() } }
init {
useLogLifecycle()
useRunningState()
useAliveView()
useCaptureVolume()
@ -485,19 +487,19 @@ private fun A11yService.useRuleChangedLog() {
}
private fun A11yService.useRunningState() {
onCreated {
A11yService.weakInstance = WeakReference(this)
A11yService.isRunning.value = true
if (!storeFlow.value.enableService) {
// https://github.com/gkd-kit/gkd/issues/754
storeFlow.update { it.copy(enableService = true) }
}
ManageService.autoStart()
}
onDestroyed {
if (storeFlow.value.enableService) {
storeFlow.update { it.copy(enableService = false) }
}
}
ManageService.autoStart()
onDestroyed {
A11yService.weakInstance = WeakReference(null)
A11yService.isRunning.value = false
}

View File

@ -18,6 +18,7 @@ import li.songe.gkd.util.componentName
import li.songe.gkd.util.lastRestartA11yServiceTimeFlow
import li.songe.gkd.util.storeFlow
import li.songe.gkd.util.toast
import li.songe.gkd.util.useLogLifecycle
class GkdTileService : TileService(), OnDestroy, OnChangeListen, OnTileClick {
override fun onStartListening() {
@ -50,6 +51,7 @@ class GkdTileService : TileService(), OnDestroy, OnChangeListen, OnTileClick {
}
init {
useLogLifecycle()
scope.launch {
combine(
A11yService.isRunning,

View File

@ -2,8 +2,8 @@ package li.songe.gkd.service
import android.app.Service
import android.content.Intent
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.combine
@ -14,45 +14,32 @@ import li.songe.gkd.app
import li.songe.gkd.notif.abNotif
import li.songe.gkd.notif.notifyService
import li.songe.gkd.permission.notificationState
import li.songe.gkd.util.OnCreate
import li.songe.gkd.util.OnDestroy
import li.songe.gkd.util.actionCountFlow
import li.songe.gkd.util.getSubsStatus
import li.songe.gkd.util.ruleSummaryFlow
import li.songe.gkd.util.storeFlow
import li.songe.gkd.util.useAliveFlow
class ManageService : Service() {
class ManageService : Service(), OnCreate, OnDestroy {
override fun onBind(intent: Intent?) = null
val scope = CoroutineScope(Dispatchers.Default)
override fun onCreate() {
super.onCreate()
isRunning.value = true
abNotif.notifyService(this)
scope.launch {
combine(
A11yService.isRunning,
storeFlow,
ruleSummaryFlow,
actionCountFlow,
) { abRunning, store, ruleSummary, count ->
if (!abRunning) return@combine "无障碍未授权"
if (!store.enableMatch) return@combine "暂停规则匹配"
if (store.useCustomNotifText) {
return@combine store.customNotifText
.replace("\${i}", ruleSummary.globalGroups.size.toString())
.replace("\${k}", ruleSummary.appSize.toString())
.replace("\${u}", ruleSummary.appGroupSize.toString())
.replace("\${n}", count.toString())
}
return@combine getSubsStatus(ruleSummary, count)
}.debounce(500L).stateIn(scope, SharingStarted.Eagerly, "").collect { text ->
abNotif.copy(text = text).notifyService(this@ManageService)
}
}
onCreated()
}
override fun onDestroy() {
super.onDestroy()
isRunning.value = false
onDestroyed()
}
val scope = MainScope().apply { onDestroyed { cancel() } }
init {
useAliveFlow(isRunning)
useNotif()
}
companion object {
@ -79,3 +66,29 @@ class ManageService : Service() {
}
}
private fun ManageService.useNotif() {
onCreated {
abNotif.notifyService(this)
scope.launch {
combine(
A11yService.isRunning,
storeFlow,
ruleSummaryFlow,
actionCountFlow,
) { abRunning, store, ruleSummary, count ->
if (!abRunning) return@combine "无障碍未授权"
if (!store.enableMatch) return@combine "暂停规则匹配"
if (store.useCustomNotifText) {
return@combine store.customNotifText
.replace("\${i}", ruleSummary.globalGroups.size.toString())
.replace("\${k}", ruleSummary.appSize.toString())
.replace("\${u}", ruleSummary.appGroupSize.toString())
.replace("\${n}", count.toString())
}
return@combine getSubsStatus(ruleSummary, count)
}.debounce(500L).stateIn(scope, SharingStarted.Eagerly, "").collect { text ->
abNotif.copy(text = text).notifyService(this@useNotif)
}
}
}
}

View File

@ -2,6 +2,8 @@ package li.songe.gkd.util
import android.view.accessibility.AccessibilityEvent
import com.blankj.utilcode.util.LogUtils
import kotlinx.coroutines.flow.MutableStateFlow
import java.util.WeakHashMap
private val callbacksMap by lazy { WeakHashMap<Any, HashMap<Int, MutableList<Any>>>() }
@ -15,13 +17,13 @@ private fun <T> Any.getCallbacks(method: Int): MutableList<T> {
interface CanOnCallback
interface OnCreate : CanOnCallback {
fun onBeforeCreate(f: () -> Unit) {
getCallbacks<() -> Unit>(1).add(f)
}
fun onBeforeCreate() {
getCallbacks<() -> Unit>(1).forEach { it() }
}
// fun onBeforeCreate(f: () -> Unit) {
// getCallbacks<() -> Unit>(1).add(f)
// }
//
// fun onBeforeCreate() {
// getCallbacks<() -> Unit>(1).forEach { it() }
// }
fun onCreated(f: () -> Unit) {
getCallbacks<() -> Unit>(2).add(f)
@ -83,7 +85,7 @@ interface OnChangeListen : CanOnCallback {
}
}
interface OnTileClick {
interface OnTileClick : CanOnCallback {
fun onTileClicked(f: () -> Unit) {
getCallbacks<() -> Unit>(14).add(f)
}
@ -92,3 +94,32 @@ interface OnTileClick {
getCallbacks<() -> Unit>(14).forEach { it() }
}
}
fun CanOnCallback.useAliveFlow(stateFlow: MutableStateFlow<Boolean>) {
if (this is OnCreate) {
onCreated { stateFlow.value = true }
}
if (this is OnDestroy) {
onDestroyed { stateFlow.value = false }
}
}
fun CanOnCallback.useLogLifecycle() {
LogUtils.d("useLogLifecycle", this)
if (this is OnCreate) {
onCreated { LogUtils.d("onCreated", this) }
}
if (this is OnDestroy) {
onDestroyed { LogUtils.d("onDestroyed", this) }
}
if (this is OnA11yConnected) {
onA11yConnected { LogUtils.d("onA11yConnected", this) }
}
if (this is OnChangeListen) {
onStartListened { LogUtils.d("onStartListened", this) }
onStopListened { LogUtils.d("onStopListened", this) }
}
if (this is OnTileClick) {
onTileClicked { LogUtils.d("onTileClicked", this) }
}
}

View File

@ -1,6 +1,5 @@
package li.songe.gkd.util
import android.annotation.SuppressLint
import android.app.Activity
import android.app.Activity.RESULT_OK
import android.content.Context
@ -22,8 +21,10 @@ import kotlin.coroutines.suspendCoroutine
// https://github.com/npes87184/ScreenShareTile/blob/master/app/src/main/java/com/npes87184/screenshottile/ScreenshotService.kt
@SuppressLint("WrongConstant")
class ScreenshotUtil(private val context: Context, private val screenshotIntent: Intent) {
class ScreenshotUtil(
private val context: Context,
private val screenshotIntent: Intent
) {
private val handler by lazy { Handler(Looper.getMainLooper()) }
private var virtualDisplay: VirtualDisplay? = null
@ -37,6 +38,13 @@ class ScreenshotUtil(private val context: Context, private val screenshotIntent:
) as MediaProjectionManager
}
private val width: Int
get() = ScreenUtils.getScreenWidth()
private val height: Int
get() = ScreenUtils.getScreenHeight()
private val dpi: Int
get() = ScreenUtils.getScreenDensityDpi()
fun destroy() {
imageReader?.setOnImageAvailableListener(null, null)
virtualDisplay?.release()
@ -101,10 +109,4 @@ class ScreenshotUtil(private val context: Context, private val screenshotIntent:
}
}, handler)
}
companion object {
private val width by lazy { ScreenUtils.getScreenWidth() }
private val height by lazy { ScreenUtils.getScreenHeight() }
private val dpi by lazy { ScreenUtils.getScreenDensityDpi() }
}
}