From d925036bd6af74ed9e111581928b20642d14bc57 Mon Sep 17 00:00:00 2001 From: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com> Date: Wed, 2 Apr 2025 00:36:08 +0800 Subject: [PATCH] Optimize the error handling logic for loading and unloading modules, this will fix the file type error, and more detail handling-2 --- .../shirkneko/zako/sukisu/ui/MainActivity.kt | 90 +++++++++++++------ .../sukisu/ui/screen/BottomBarDestination.kt | 2 +- .../shirkneko/zako/sukisu/ui/screen/Home.kt | 52 +++++++++-- .../shirkneko/zako/sukisu/ui/screen/kpm.kt | 34 +++++-- .../shirkneko/zako/sukisu/ui/util/KsuCli.kt | 10 +-- .../src/main/res/values-zh-rCN/strings.xml | 5 ++ manager/app/src/main/res/values/strings.xml | 5 ++ 7 files changed, 151 insertions(+), 47 deletions(-) diff --git a/manager/app/src/main/java/shirkneko/zako/sukisu/ui/MainActivity.kt b/manager/app/src/main/java/shirkneko/zako/sukisu/ui/MainActivity.kt index 15099c52..f2153d20 100644 --- a/manager/app/src/main/java/shirkneko/zako/sukisu/ui/MainActivity.kt +++ b/manager/app/src/main/java/shirkneko/zako/sukisu/ui/MainActivity.kt @@ -49,6 +49,7 @@ import shirkneko.zako.sukisu.ui.theme.KernelSUTheme import shirkneko.zako.sukisu.ui.theme.loadCustomBackground import shirkneko.zako.sukisu.ui.theme.loadThemeMode import shirkneko.zako.sukisu.ui.util.LocalSnackbarHost +import shirkneko.zako.sukisu.ui.util.getKpmVersion import shirkneko.zako.sukisu.ui.util.rootAvailable import shirkneko.zako.sukisu.ui.util.install @@ -107,6 +108,7 @@ private fun BottomBar(navController: NavHostController) { val navigator = navController.rememberDestinationsNavigator() val isManager = Natives.becomeManager(ksuApp.packageName) val fullFeatured = isManager && !Natives.requireNewKernel() && rootAvailable() + val kpmVersion = getKpmVersion() // 获取卡片颜色和透明度 val cardColor = MaterialTheme.colorScheme.secondaryContainer @@ -122,35 +124,69 @@ private fun BottomBar(navController: NavHostController) { ) ) { BottomBarDestination.entries.forEach { destination -> - if (!fullFeatured && destination.rootRequired) return@forEach - val isCurrentDestOnBackStack by navController.isRouteOnBackStackAsState(destination.direction) - NavigationBarItem( - selected = isCurrentDestOnBackStack, - onClick = { - if (isCurrentDestOnBackStack) { - navigator.popBackStack(destination.direction, false) - } - navigator.navigate(destination.direction) { - popUpTo(NavGraphs.root) { - saveState = true + if (destination == BottomBarDestination.Kpm) { + if (kpmVersion.isNotEmpty() && !kpmVersion.startsWith("Error")) { + if (!fullFeatured && destination.rootRequired) return@forEach + val isCurrentDestOnBackStack by navController.isRouteOnBackStackAsState(destination.direction) + NavigationBarItem( + selected = isCurrentDestOnBackStack, + onClick = { + if (isCurrentDestOnBackStack) { + navigator.popBackStack(destination.direction, false) + } + navigator.navigate(destination.direction) { + popUpTo(NavGraphs.root) { + saveState = true + } + launchSingleTop = true + restoreState = true + } + }, + icon = { + if (isCurrentDestOnBackStack) { + Icon(destination.iconSelected, stringResource(destination.label)) + } else { + Icon(destination.iconNotSelected, stringResource(destination.label)) + } + }, + label = { Text(stringResource(destination.label)) }, + alwaysShowLabel = false, + colors = androidx.compose.material3.NavigationBarItemDefaults.colors( + unselectedTextColor = MaterialTheme.colorScheme.onSurfaceVariant + ) + ) + } + } else { + if (!fullFeatured && destination.rootRequired) return@forEach + val isCurrentDestOnBackStack by navController.isRouteOnBackStackAsState(destination.direction) + NavigationBarItem( + selected = isCurrentDestOnBackStack, + onClick = { + if (isCurrentDestOnBackStack) { + navigator.popBackStack(destination.direction, false) } - launchSingleTop = true - restoreState = true - } - }, - icon = { - if (isCurrentDestOnBackStack) { - Icon(destination.iconSelected, stringResource(destination.label)) - } else { - Icon(destination.iconNotSelected, stringResource(destination.label)) - } - }, - label = { Text(stringResource(destination.label)) }, - alwaysShowLabel = false, - colors = androidx.compose.material3.NavigationBarItemDefaults.colors( - unselectedTextColor = MaterialTheme.colorScheme.onSurfaceVariant + navigator.navigate(destination.direction) { + popUpTo(NavGraphs.root) { + saveState = true + } + launchSingleTop = true + restoreState = true + } + }, + icon = { + if (isCurrentDestOnBackStack) { + Icon(destination.iconSelected, stringResource(destination.label)) + } else { + Icon(destination.iconNotSelected, stringResource(destination.label)) + } + }, + label = { Text(stringResource(destination.label)) }, + alwaysShowLabel = false, + colors = androidx.compose.material3.NavigationBarItemDefaults.colors( + unselectedTextColor = MaterialTheme.colorScheme.onSurfaceVariant + ) ) - ) + } } } } \ No newline at end of file diff --git a/manager/app/src/main/java/shirkneko/zako/sukisu/ui/screen/BottomBarDestination.kt b/manager/app/src/main/java/shirkneko/zako/sukisu/ui/screen/BottomBarDestination.kt index 285acbd9..0812085b 100644 --- a/manager/app/src/main/java/shirkneko/zako/sukisu/ui/screen/BottomBarDestination.kt +++ b/manager/app/src/main/java/shirkneko/zako/sukisu/ui/screen/BottomBarDestination.kt @@ -21,8 +21,8 @@ enum class BottomBarDestination( val rootRequired: Boolean, ) { Home(HomeScreenDestination, R.string.home, Icons.Filled.Home, Icons.Outlined.Home, false), + Kpm(KpmScreenDestination, R.string.kpm_title, Icons.Filled.Build, Icons.Outlined.Build, true), SuperUser(SuperUserScreenDestination, R.string.superuser, Icons.Filled.Security, Icons.Outlined.Security, true), Module(ModuleScreenDestination, R.string.module, Icons.Filled.Apps, Icons.Outlined.Apps, true), - Kpm(KpmScreenDestination, R.string.kpm_title, Icons.Filled.Build, Icons.Outlined.Build, true), Settings(SettingScreenDestination, R.string.settings, Icons.Filled.Settings, Icons.Outlined.Settings, false), } diff --git a/manager/app/src/main/java/shirkneko/zako/sukisu/ui/screen/Home.kt b/manager/app/src/main/java/shirkneko/zako/sukisu/ui/screen/Home.kt index 51fc6f33..0e407dd8 100644 --- a/manager/app/src/main/java/shirkneko/zako/sukisu/ui/screen/Home.kt +++ b/manager/app/src/main/java/shirkneko/zako/sukisu/ui/screen/Home.kt @@ -51,6 +51,10 @@ import androidx.compose.animation.shrinkVertically import androidx.compose.runtime.saveable.rememberSaveable import shirkneko.zako.sukisu.ui.theme.CardConfig import androidx.core.content.edit +import java.io.BufferedReader +import java.io.InputStreamReader +import java.util.Scanner +import java.util.zip.GZIPInputStream import kotlin.random.Random @OptIn(ExperimentalMaterial3Api::class) @@ -333,6 +337,14 @@ private fun StatusCard( text = stringResource(R.string.home_module_count, getModuleCount()), style = MaterialTheme.typography.bodyMedium ) + val kpmVersion = getKpmVersion() + if (kpmVersion.isNotEmpty() && !kpmVersion.startsWith("Error")) { + Spacer(Modifier.height(4.dp)) + Text( + text = stringResource(R.string.home_kpm_module, getKpmModuleCount()), + style = MaterialTheme.typography.bodyMedium + ) + } Spacer(modifier = Modifier.height(4.dp)) val suSFS = getSuSFS() @@ -555,18 +567,28 @@ private fun InfoCard() { InfoCardItem(stringResource(R.string.home_selinux_status), getSELinuxStatus()) - if (!isSimpleMode){ - Spacer(Modifier.height(16.dp)) + + if (!isSimpleMode) { val kpmVersion = getKpmVersion() - val displayVersion = if (kpmVersion.isEmpty() || kpmVersion.startsWith("Error")) { - stringResource(R.string.not_supported) + var displayVersion: String + val isKpmConfigured = checkKpmConfigured() + + if (kpmVersion.isEmpty() || kpmVersion.startsWith("Error")) { + val statusText = if (isKpmConfigured) { + stringResource(R.string.kernel_patched) + } else { + stringResource(R.string.kernel_not_enabled) + } + displayVersion = "${stringResource(R.string.not_supported)} ($statusText)" } else { - kpmVersion + displayVersion = "${stringResource(R.string.supported)} ($kpmVersion)" } + Spacer(Modifier.height(16.dp)) InfoCardItem(stringResource(R.string.home_kpm_version), displayVersion) } + if (!isSimpleMode) { Spacer(modifier = Modifier.height(16.dp)) @@ -645,4 +667,24 @@ private fun getDeviceModel(context: Context): String { } catch (e: Exception) { Build.DEVICE } +} + +private fun checkKpmConfigured(): Boolean { + try { + val process = Runtime.getRuntime().exec("su -c cat /proc/config.gz") + val inputStream = process.inputStream + val gzipInputStream = GZIPInputStream(inputStream) + val reader = BufferedReader(InputStreamReader(gzipInputStream)) + + var line: String? + while (reader.readLine().also { line = it } != null) { + if (line?.contains("CONFIG_KPM=y") == true) { + return true + } + } + reader.close() + } catch (e: Exception) { + e.printStackTrace() + } + return false } \ No newline at end of file diff --git a/manager/app/src/main/java/shirkneko/zako/sukisu/ui/screen/kpm.kt b/manager/app/src/main/java/shirkneko/zako/sukisu/ui/screen/kpm.kt index 3ab01997..d3a59f39 100644 --- a/manager/app/src/main/java/shirkneko/zako/sukisu/ui/screen/kpm.kt +++ b/manager/app/src/main/java/shirkneko/zako/sukisu/ui/screen/kpm.kt @@ -4,8 +4,6 @@ import android.content.Intent import android.util.Log import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts -import androidx.compose.animation.core.Spring -import androidx.compose.animation.core.SpringSpec import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items @@ -92,6 +90,15 @@ fun KpmScreen( } } + if (!tempFile.name.endsWith(".kpm")) { + snackBarHost.showSnackbar( + message = "文件类型不正确,请选择 .kpm 文件", + duration = SnackbarDuration.Short + ) + tempFile.delete() + return@launch + } + val confirmResult = confirmDialog.awaitConfirm( title = kpmInstall, content = kpmInstallConfirm, @@ -102,10 +109,15 @@ fun KpmScreen( if (confirmResult == ConfirmResult.Confirmed) { val success = loadingDialog.withLoading { try { - loadKpmModule(tempFile.absolutePath) - true + val loadResult = loadKpmModule(tempFile.absolutePath) + if (true && loadResult.startsWith("Error")) { + Log.e("KsuCli", "Failed to load KPM module: $loadResult") + false + } else { + true + } } catch (e: Exception) { - Log.e("KsuCli", "Failed to load KPM module: ${e.message}") + Log.e("KsuCli", "Failed to load KPM module: ${e.message}", e) false } } @@ -234,13 +246,19 @@ fun KpmScreen( if (confirmResult == ConfirmResult.Confirmed) { val success = loadingDialog.withLoading { try { - unloadKpmModule(module.id) - true + val unloadResult = unloadKpmModule(module.id) + if (true && unloadResult.startsWith("Error")) { + Log.e("KsuCli", "Failed to unload KPM module: $unloadResult") + false + } else { + true + } } catch (e: Exception) { - Log.e("KsuCli", "Failed to unload KPM module: ${e.message}") + Log.e("KsuCli", "Failed to unload KPM module: ${e.message}", e) false } } + if (success) { viewModel.fetchModuleList() snackBarHost.showSnackbar( diff --git a/manager/app/src/main/java/shirkneko/zako/sukisu/ui/util/KsuCli.kt b/manager/app/src/main/java/shirkneko/zako/sukisu/ui/util/KsuCli.kt index 9cd8bd29..178531d6 100644 --- a/manager/app/src/main/java/shirkneko/zako/sukisu/ui/util/KsuCli.kt +++ b/manager/app/src/main/java/shirkneko/zako/sukisu/ui/util/KsuCli.kt @@ -486,18 +486,16 @@ private fun getKpmmgrPath(): String { } -fun loadKpmModule(path: String, args: String? = null): Boolean { +fun loadKpmModule(path: String, args: String? = null): String { val shell = getRootShell() val cmd = "${getKpmmgrPath()} load $path ${args ?: ""}" - val result = ShellUtils.fastCmd(shell, cmd) - return result.contains("Success", ignoreCase = true) + return ShellUtils.fastCmd(shell, cmd) } -fun unloadKpmModule(name: String): Boolean { +fun unloadKpmModule(name: String): String { val shell = getRootShell() val cmd = "${getKpmmgrPath()} unload $name" - val result = ShellUtils.fastCmd(shell, cmd) - return result.trim().isEmpty() || result.trim() == "0" + return ShellUtils.fastCmd(shell, cmd) } fun getKpmModuleCount(): Int { 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 cf8d3779..c9dc4555 100644 --- a/manager/app/src/main/res/values-zh-rCN/strings.xml +++ b/manager/app/src/main/res/values-zh-rCN/strings.xml @@ -239,6 +239,11 @@ 成功 错误 不支持 + 支持 + KPM 模块数:%d + KPM 文件无效 + 内核未进行补丁 + 内核未配置 以下内核模块功能由KernelPatch开发,经过修改后加入SukiSU Ultra的内核模块功能 SukiSU Ultra展望 SukiSU Ultra未来将会成为一个相对独立的KSU分支,但是依然感谢官方KernelSU和MKSU等做出的贡献 diff --git a/manager/app/src/main/res/values/strings.xml b/manager/app/src/main/res/values/strings.xml index a38c2904..98ba0564 100644 --- a/manager/app/src/main/res/values/strings.xml +++ b/manager/app/src/main/res/values/strings.xml @@ -245,4 +245,9 @@ failed SukiSU Ultra will be a relatively independent branch of KSU in the future, but thanks to the official KernelSU and MKSU etc. for their contributions! unsupported + supported + Number of KPM modules:%d + Invalid KPM file + Kernel not patched + Kernel not configured