From 7bf13fbfca57d878af8dc1b208da40915a922086 Mon Sep 17 00:00:00 2001 From: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com> Date: Wed, 22 Oct 2025 22:42:26 +0800 Subject: [PATCH] manager: Add an option to exclude the current application and certain system calls from the log viewer. --- .../sukisu/ultra/ui/screen/LogViewerScreen.kt | 96 ++++++++++++++++++- .../src/main/res/values-zh-rCN/strings.xml | 2 + manager/app/src/main/res/values/strings.xml | 2 + 3 files changed, 96 insertions(+), 4 deletions(-) diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/screen/LogViewerScreen.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/screen/LogViewerScreen.kt index f9b8888d..4f12d316 100644 --- a/manager/app/src/main/java/com/sukisu/ultra/ui/screen/LogViewerScreen.kt +++ b/manager/app/src/main/java/com/sukisu/ultra/ui/screen/LogViewerScreen.kt @@ -1,5 +1,6 @@ package com.sukisu.ultra.ui.screen +import android.content.Context import androidx.compose.animation.* import androidx.compose.foundation.background import androidx.compose.foundation.clickable @@ -41,6 +42,8 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import java.time.* import java.time.format.DateTimeFormatter +import android.os.Process.myUid +import androidx.core.content.edit private val SPACING_SMALL = 4.dp private val SPACING_MEDIUM = 8.dp @@ -65,9 +68,30 @@ enum class LogType(val displayName: String, val color: Color) { UNKNOWN("UNKNOWN", Color(0xFF757575)) } +enum class LogExclType(val displayName: String, val color: Color) { + CURRENT_APP("Current app", Color(0xFF9E9E9E)), + PRCTL_STAR("prctl_*", Color(0xFF00BCD4)), + PRCTL_UNKNOWN("prctl_unknown", Color(0xFF00BCD4)), + SETUID("setuid", Color(0xFF00BCD4)) +} + private val utcFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss") private val localFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss") +private fun saveExcludedSubTypes(context: Context, types: Set) { + val prefs = context.getSharedPreferences("sulog", Context.MODE_PRIVATE) + val nameSet = types.map { it.name }.toSet() + prefs.edit { putStringSet("excluded_subtypes", nameSet) } +} + +private fun loadExcludedSubTypes(context: Context): Set { + val prefs = context.getSharedPreferences("sulog", Context.MODE_PRIVATE) + val nameSet = prefs.getStringSet("excluded_subtypes", emptySet()) ?: emptySet() + return nameSet.mapNotNull { name -> + LogExclType.entries.firstOrNull { it.name == name } + }.toSet() +} + @OptIn(ExperimentalMaterial3Api::class) @Destination @Composable @@ -83,14 +107,40 @@ fun LogViewerScreen(navigator: DestinationsNavigator) { var filterType by rememberSaveable { mutableStateOf(null) } var searchQuery by rememberSaveable { mutableStateOf("") } var showSearchBar by rememberSaveable { mutableStateOf(false) } + val currentUid = remember { myUid().toString() } - val filteredEntries = remember(logEntries, filterType, searchQuery) { + val initialExcluded = remember { + loadExcludedSubTypes(context) + } + + var excludedSubTypes by rememberSaveable { mutableStateOf(initialExcluded) } + + LaunchedEffect(excludedSubTypes) { + saveExcludedSubTypes(context, excludedSubTypes) + } + + val filteredEntries = remember( + logEntries, filterType, searchQuery, excludedSubTypes + ) { logEntries.filter { entry -> - val matchesFilter = filterType == null || entry.type == filterType val matchesSearch = searchQuery.isEmpty() || entry.comm.contains(searchQuery, ignoreCase = true) || entry.details.contains(searchQuery, ignoreCase = true) || entry.uid.contains(searchQuery, ignoreCase = true) + + // 排除本应用 + if (LogExclType.CURRENT_APP in excludedSubTypes && entry.uid == currentUid) return@filter false + + // 排除 SYSCALL 子类型 + if (entry.type == LogType.SYSCALL) { + val detail = entry.details + if (LogExclType.PRCTL_STAR in excludedSubTypes && detail.startsWith("Syscall: prctl") && !detail.startsWith("Syscall: prctl_unknown")) return@filter false + if (LogExclType.PRCTL_UNKNOWN in excludedSubTypes && detail.startsWith("Syscall: prctl_unknown")) return@filter false + if (LogExclType.SETUID in excludedSubTypes && detail.startsWith("Syscall: setuid")) return@filter false + } + + // 普通类型筛选 + val matchesFilter = filterType == null || entry.type == filterType matchesFilter && matchesSearch } } @@ -161,7 +211,14 @@ fun LogViewerScreen(navigator: DestinationsNavigator) { filterType = filterType, onFilterTypeSelected = { filterType = it }, logCount = filteredEntries.size, - totalCount = logEntries.size + totalCount = logEntries.size, + excludedSubTypes = excludedSubTypes, + onExcludeToggle = { excl -> + excludedSubTypes = if (excl in excludedSubTypes) + excludedSubTypes - excl + else + excludedSubTypes + excl + } ) // 日志列表 @@ -200,7 +257,9 @@ private fun LogControlPanel( filterType: LogType?, onFilterTypeSelected: (LogType?) -> Unit, logCount: Int, - totalCount: Int + totalCount: Int, + excludedSubTypes: Set, + onExcludeToggle: (LogExclType) -> Unit ) { Card( modifier = Modifier @@ -273,6 +332,35 @@ private fun LogControlPanel( Spacer(modifier = Modifier.height(SPACING_MEDIUM)) + Text( + text = stringResource(R.string.log_viewer_exclude_subtypes), + style = MaterialTheme.typography.titleSmall, + color = MaterialTheme.colorScheme.primary + ) + Spacer(modifier = Modifier.height(SPACING_MEDIUM)) + + LazyRow(horizontalArrangement = Arrangement.spacedBy(SPACING_MEDIUM)) { + items(LogExclType.entries.toTypedArray()) { excl -> + val label = if (excl == LogExclType.CURRENT_APP) + stringResource(R.string.log_viewer_exclude_current_app) + else excl.displayName + + FilterChip( + onClick = { onExcludeToggle(excl) }, + label = { Text(label) }, + selected = excl in excludedSubTypes, + leadingIcon = { + Box( + modifier = Modifier + .size(8.dp) + .background(excl.color, RoundedCornerShape(4.dp)) + ) + } + ) + } + } + Spacer(modifier = Modifier.height(SPACING_MEDIUM)) + // 统计信息 Text( text = stringResource(R.string.log_viewer_showing_entries, logCount, totalCount), diff --git a/manager/app/src/main/res/values-zh-rCN/strings.xml b/manager/app/src/main/res/values-zh-rCN/strings.xml index 08d125b8..416c6f80 100644 --- a/manager/app/src/main/res/values-zh-rCN/strings.xml +++ b/manager/app/src/main/res/values-zh-rCN/strings.xml @@ -707,4 +707,6 @@ 清除搜索 查看使用日志 查看 KernelSU 超级用户访问日志 + 排除子类型 + 当前应用 diff --git a/manager/app/src/main/res/values/strings.xml b/manager/app/src/main/res/values/strings.xml index 2eaf3eef..db2e0afb 100644 --- a/manager/app/src/main/res/values/strings.xml +++ b/manager/app/src/main/res/values/strings.xml @@ -716,4 +716,6 @@ Important Note:\n Clear search View Usage Logs View KernelSU superuser access logs + Exclude sub-types + Current App \ No newline at end of file