manager: Update and add SuSFS related settings and functions.

This commit is contained in:
ShirkNeko
2025-06-14 20:00:16 +08:00
parent 7097986cf5
commit 97e367aa92
5 changed files with 2090 additions and 288 deletions

View File

@@ -1,5 +1,6 @@
package com.sukisu.ultra.ui.util
import android.annotation.SuppressLint
import android.content.Context
import android.content.SharedPreferences
import android.widget.Toast
@@ -21,11 +22,43 @@ object SuSFSManager {
private const val KEY_IS_ENABLED = "is_enabled"
private const val KEY_AUTO_START_ENABLED = "auto_start_enabled"
private const val KEY_LAST_APPLIED_VALUE = "last_applied_value"
private const val KEY_SUS_PATHS = "sus_paths"
private const val KEY_SUS_MOUNTS = "sus_mounts"
private const val KEY_TRY_UMOUNTS = "try_umounts"
private const val KEY_ANDROID_DATA_PATH = "android_data_path"
private const val KEY_SDCARD_PATH = "sdcard_path"
private const val SUSFS_BINARY_NAME = "ksu_susfs"
private const val DEFAULT_UNAME = "default"
private const val STARTUP_SCRIPT_PATH = "/data/adb/service.d/susfs_startup.sh"
private const val SUSFS_TARGET_PATH = "/data/adb/ksu/bin/$SUSFS_BINARY_NAME"
/**
* 启用功能状态数据类
*/
data class EnabledFeature(
val name: String,
val isEnabled: Boolean
)
/**
* 功能配置映射数据类
*/
private data class FeatureMapping(
val id: String,
val config: String
)
/**
* 执行Shell命令并返回输出
*/
private fun runCmd(shell: Shell, cmd: String): String {
return shell.newJob()
.add(cmd)
.to(mutableListOf<String>(), null)
.exec().out
.joinToString("\n")
}
/**
* 获取Root Shell实例
*/
@@ -101,6 +134,93 @@ object SuSFSManager {
return getPrefs(context).getBoolean(KEY_AUTO_START_ENABLED, false)
}
/**
* 保存SUS路径列表
*/
fun saveSusPaths(context: Context, paths: Set<String>) {
getPrefs(context).edit().apply {
putStringSet(KEY_SUS_PATHS, paths)
apply()
}
}
/**
* 获取SUS路径列表
*/
fun getSusPaths(context: Context): Set<String> {
return getPrefs(context).getStringSet(KEY_SUS_PATHS, emptySet()) ?: emptySet()
}
/**
* 保存SUS挂载列表
*/
fun saveSusMounts(context: Context, mounts: Set<String>) {
getPrefs(context).edit().apply {
putStringSet(KEY_SUS_MOUNTS, mounts)
apply()
}
}
/**
* 获取SUS挂载列表
*/
fun getSusMounts(context: Context): Set<String> {
return getPrefs(context).getStringSet(KEY_SUS_MOUNTS, emptySet()) ?: emptySet()
}
/**
* 保存尝试卸载列表
*/
fun saveTryUmounts(context: Context, umounts: Set<String>) {
getPrefs(context).edit().apply {
putStringSet(KEY_TRY_UMOUNTS, umounts)
apply()
}
}
/**
* 获取尝试卸载列表
*/
fun getTryUmounts(context: Context): Set<String> {
return getPrefs(context).getStringSet(KEY_TRY_UMOUNTS, emptySet()) ?: emptySet()
}
/**
* 保存Android Data路径
*/
fun saveAndroidDataPath(context: Context, path: String) {
getPrefs(context).edit().apply {
putString(KEY_ANDROID_DATA_PATH, path)
apply()
}
}
/**
* 获取Android Data路径
*/
@SuppressLint("SdCardPath")
fun getAndroidDataPath(context: Context): String {
return getPrefs(context).getString(KEY_ANDROID_DATA_PATH, "/sdcard/Android/data") ?: "/sdcard/Android/data"
}
/**
* 保存SD卡路径
*/
fun saveSdcardPath(context: Context, path: String) {
getPrefs(context).edit().apply {
putString(KEY_SDCARD_PATH, path)
apply()
}
}
/**
* 获取SD卡路径
*/
@SuppressLint("SdCardPath")
fun getSdcardPath(context: Context): String {
return getPrefs(context).getString(KEY_SDCARD_PATH, "/sdcard") ?: "/sdcard"
}
/**
* 从assets复制ksu_susfs文件到/data/adb/ksu/bin/
*/
@@ -151,26 +271,81 @@ object SuSFSManager {
/**
* 创建开机自启动脚本
*/
private suspend fun createStartupScript(unameValue: String): Boolean = withContext(Dispatchers.IO) {
@SuppressLint("SdCardPath")
private suspend fun createStartupScript(context: Context): Boolean = withContext(Dispatchers.IO) {
try {
val scriptContent = """#!/system/bin/sh
# SuSFS 开机自启动脚本
# 由 KernelSU Manager 自动生成
val unameValue = getUnameValue(context)
val susPaths = getSusPaths(context)
val susMounts = getSusMounts(context)
val tryUmounts = getTryUmounts(context)
val androidDataPath = getAndroidDataPath(context)
val sdcardPath = getSdcardPath(context)
# 等待系统完全启动
sleep 30
val scriptContent = buildString {
appendLine("#!/system/bin/sh")
appendLine("# SuSFS 开机自启动脚本")
appendLine("# 由 KernelSU Manager 自动生成")
appendLine()
appendLine("# 等待系统完全启动")
appendLine("sleep 60")
appendLine()
appendLine("# 检查二进制文件是否存在")
appendLine("if [ -f \"$SUSFS_TARGET_PATH\" ]; then")
appendLine(" # 创建日志目录")
appendLine(" mkdir -p /data/adb/ksu/log")
appendLine()
# 检查二进制文件是否存在
if [ -f "$SUSFS_TARGET_PATH" ]; then
# 执行 SuSFS setUname 命令
$SUSFS_TARGET_PATH set_uname '$unameValue' '$DEFAULT_UNAME'
// 设置Android Data路径
if (androidDataPath != "/sdcard/Android/data") {
appendLine(" # 设置Android Data路径")
appendLine(" $SUSFS_TARGET_PATH set_android_data_root_path '$androidDataPath'")
appendLine(" echo \"\\$(date): Android Data路径设置为: $androidDataPath\" >> /data/adb/ksu/log/susfs_startup.log")
}
# 记录日志
echo "\$(date): SuSFS setUname executed with value: $unameValue" >> /data/adb/ksu/log/susfs_startup.log
else
echo "\$(date): SuSFS binary not found at $SUSFS_TARGET_PATH" >> /data/adb/ksu/log/susfs_startup.log
fi
"""
// 设置SD卡路径
if (sdcardPath != "/sdcard") {
appendLine(" # 设置SD卡路径")
appendLine(" $SUSFS_TARGET_PATH set_sdcard_root_path '$sdcardPath'")
appendLine(" echo \"\\$(date): SD卡路径设置为: $sdcardPath\" >> /data/adb/ksu/log/susfs_startup.log")
}
// 添加SUS路径
susPaths.forEach { path ->
appendLine(" # 添加SUS路径: $path")
appendLine(" $SUSFS_TARGET_PATH add_sus_path '$path'")
appendLine(" echo \"\\$(date): 添加SUS路径: $path\" >> /data/adb/ksu/log/susfs_startup.log")
}
// 添加SUS挂载
susMounts.forEach { mount ->
appendLine(" # 添加SUS挂载: $mount")
appendLine(" $SUSFS_TARGET_PATH add_sus_mount '$mount'")
appendLine(" echo \"\\$(date): 添加SUS挂载: $mount\" >> /data/adb/ksu/log/susfs_startup.log")
}
// 添加尝试卸载
tryUmounts.forEach { umount ->
val parts = umount.split("|")
if (parts.size == 2) {
val path = parts[0]
val mode = parts[1]
appendLine(" # 添加尝试卸载: $path (模式: $mode)")
appendLine(" $SUSFS_TARGET_PATH add_try_umount '$path' $mode")
appendLine(" echo \"\\$(date): 添加尝试卸载: $path (模式: $mode)\" >> /data/adb/ksu/log/susfs_startup.log")
}
}
// 设置uname
if (unameValue != DEFAULT_UNAME) {
appendLine(" # 设置uname")
appendLine(" $SUSFS_TARGET_PATH set_uname '$unameValue' '$DEFAULT_UNAME'")
appendLine(" echo \"\\$(date): 设置uname为: $unameValue\" >> /data/adb/ksu/log/susfs_startup.log")
}
appendLine("else")
appendLine(" echo \"\\$(date): SuSFS二进制文件未找到: $SUSFS_TARGET_PATH\" >> /data/adb/ksu/log/susfs_startup.log")
appendLine("fi")
}
val shell = getRootShell()
val commands = arrayOf(
@@ -209,6 +384,306 @@ fi
}
}
/**
* 执行SuSFS命令
*/
private suspend fun executeSusfsCommand(context: Context, command: String): Boolean = withContext(Dispatchers.IO) {
try {
// 确保二进制文件存在
val binaryPath = copyBinaryFromAssets(context)
if (binaryPath == null) {
withContext(Dispatchers.Main) {
Toast.makeText(
context,
context.getString(R.string.susfs_binary_not_found),
Toast.LENGTH_SHORT
).show()
}
return@withContext false
}
// 执行命令
val fullCommand = "$binaryPath $command"
val result = getRootShell().newJob().add(fullCommand).exec()
if (!result.isSuccess) {
withContext(Dispatchers.Main) {
val errorOutput = result.out.joinToString("\n") + "\n" + result.err.joinToString("\n")
Toast.makeText(
context,
context.getString(R.string.susfs_command_failed) + "\n$errorOutput",
Toast.LENGTH_LONG
).show()
}
}
result.isSuccess
} catch (e: Exception) {
e.printStackTrace()
withContext(Dispatchers.Main) {
Toast.makeText(
context,
context.getString(R.string.susfs_command_error, e.message ?: "Unknown error"),
Toast.LENGTH_SHORT
).show()
}
false
}
}
/**
* 获取功能配置映射表
*/
private fun getFeatureMappings(): List<FeatureMapping> {
return listOf(
FeatureMapping("status_sus_path", "CONFIG_KSU_SUSFS_SUS_PATH"),
FeatureMapping("status_sus_mount", "CONFIG_KSU_SUSFS_SUS_MOUNT"),
FeatureMapping("status_auto_default_mount", "CONFIG_KSU_SUSFS_AUTO_ADD_SUS_KSU_DEFAULT_MOUNT"),
FeatureMapping("status_auto_bind_mount", "CONFIG_KSU_SUSFS_AUTO_ADD_SUS_BIND_MOUNT"),
FeatureMapping("status_sus_kstat", "CONFIG_KSU_SUSFS_SUS_KSTAT"),
FeatureMapping("status_try_umount", "CONFIG_KSU_SUSFS_TRY_UMOUNT"),
FeatureMapping("status_auto_try_umount_bind", "CONFIG_KSU_SUSFS_AUTO_ADD_TRY_UMOUNT_FOR_BIND_MOUNT"),
FeatureMapping("status_spoof_uname", "CONFIG_KSU_SUSFS_SPOOF_UNAME"),
FeatureMapping("status_enable_log", "CONFIG_KSU_SUSFS_ENABLE_LOG"),
FeatureMapping("status_hide_symbols", "CONFIG_KSU_SUSFS_HIDE_KSU_SUSFS_SYMBOLS"),
FeatureMapping("status_spoof_cmdline", "CONFIG_KSU_SUSFS_SPOOF_CMDLINE_OR_BOOTCONFIG"),
FeatureMapping("status_open_redirect", "CONFIG_KSU_SUSFS_OPEN_REDIRECT"),
FeatureMapping("status_magic_mount", "CONFIG_KSU_SUSFS_HAS_MAGIC_MOUNT"),
FeatureMapping("status_overlayfs_auto_kstat", "CONFIG_KSU_SUSFS_SUS_OVERLAYFS")
)
}
/**
* 获取启用功能状态
*/
suspend fun getEnabledFeatures(context: Context): List<EnabledFeature> = withContext(Dispatchers.IO) {
try {
// 每次都重新执行命令获取最新状态
val shell = getRootShell()
// 首先检查二进制文件是否存在于目标位置
val checkResult = shell.newJob().add("test -f '$SUSFS_TARGET_PATH'").exec()
val binaryPath = if (checkResult.isSuccess) {
// 如果目标位置存在,直接使用
SUSFS_TARGET_PATH
} else {
// 如果不存在尝试从assets复制
copyBinaryFromAssets(context)
}
if (binaryPath == null) {
return@withContext emptyList()
}
// 使用runCmd执行show enabled_features命令获取实时状态
val command = "$binaryPath show enabled_features"
val output = runCmd(shell, command)
if (output.isNotEmpty()) {
parseEnabledFeatures(context, output)
} else {
// 如果命令输出为空,返回空列表
emptyList()
}
} catch (e: Exception) {
e.printStackTrace()
emptyList()
}
}
/**
* 解析启用功能状态输出
*/
private fun parseEnabledFeatures(context: Context, output: String): List<EnabledFeature> {
val features = mutableListOf<EnabledFeature>()
// 将输出按行分割并保存到集合中进行快速查找
val outputLines = output.lines().map { it.trim() }.filter { it.isNotEmpty() }.toSet()
// 获取功能配置映射表
val featureMappings = getFeatureMappings()
// 定义功能名称映射id到显示名称
val featureNameMap = mapOf(
"status_sus_path" to context.getString(R.string.sus_path_feature_label),
"status_sus_mount" to context.getString(R.string.sus_mount_feature_label),
"status_try_umount" to context.getString(R.string.try_umount_feature_label),
"status_spoof_uname" to context.getString(R.string.spoof_uname_feature_label),
"status_spoof_cmdline" to context.getString(R.string.spoof_cmdline_feature_label),
"status_open_redirect" to context.getString(R.string.open_redirect_feature_label),
"status_enable_log" to context.getString(R.string.enable_log_feature_label),
"status_auto_default_mount" to context.getString(R.string.auto_default_mount_feature_label),
"status_auto_bind_mount" to context.getString(R.string.auto_bind_mount_feature_label),
"status_auto_try_umount_bind" to context.getString(R.string.auto_try_umount_bind_feature_label),
"status_hide_symbols" to context.getString(R.string.hide_symbols_feature_label),
"status_sus_kstat" to context.getString(R.string.sus_kstat_feature_label),
"status_magic_mount" to context.getString(R.string.magic_mount_feature_label),
"status_overlayfs_auto_kstat" to context.getString(R.string.overlayfs_auto_kstat_feature_label)
)
// 根据映射表检查每个功能的启用状态
featureMappings.forEach { mapping ->
val displayName = featureNameMap[mapping.id] ?: mapping.id
val isEnabled = outputLines.contains(mapping.config)
features.add(EnabledFeature(displayName, isEnabled))
}
return features.sortedBy { it.name }
}
/**
* 添加SUS路径
*/
suspend fun addSusPath(context: Context, path: String): Boolean {
val success = executeSusfsCommand(context, "add_sus_path '$path'")
if (success) {
val currentPaths = getSusPaths(context).toMutableSet()
currentPaths.add(path)
saveSusPaths(context, currentPaths)
// 如果开启了开机自启动,更新启动脚本
if (isAutoStartEnabled(context)) {
createStartupScript(context)
}
}
return success
}
/**
* 移除SUS路径
*/
suspend fun removeSusPath(context: Context, path: String): Boolean {
val currentPaths = getSusPaths(context).toMutableSet()
currentPaths.remove(path)
saveSusPaths(context, currentPaths)
// 如果开启了开机自启动,更新启动脚本
if (isAutoStartEnabled(context)) {
createStartupScript(context)
}
withContext(Dispatchers.Main) {
Toast.makeText(context, "已移除SUS路径: $path", Toast.LENGTH_SHORT).show()
}
return true
}
/**
* 添加SUS挂载
*/
suspend fun addSusMount(context: Context, mount: String): Boolean {
val success = executeSusfsCommand(context, "add_sus_mount '$mount'")
if (success) {
val currentMounts = getSusMounts(context).toMutableSet()
currentMounts.add(mount)
saveSusMounts(context, currentMounts)
// 如果开启了开机自启动,更新启动脚本
if (isAutoStartEnabled(context)) {
createStartupScript(context)
}
}
return success
}
/**
* 移除SUS挂载
*/
suspend fun removeSusMount(context: Context, mount: String): Boolean {
val currentMounts = getSusMounts(context).toMutableSet()
currentMounts.remove(mount)
saveSusMounts(context, currentMounts)
// 如果开启了开机自启动,更新启动脚本
if (isAutoStartEnabled(context)) {
createStartupScript(context)
}
withContext(Dispatchers.Main) {
Toast.makeText(context, "已移除SUS挂载: $mount", Toast.LENGTH_SHORT).show()
}
return true
}
/**
* 添加尝试卸载
*/
suspend fun addTryUmount(context: Context, path: String, mode: Int): Boolean {
val success = executeSusfsCommand(context, "add_try_umount '$path' $mode")
if (success) {
val currentUmounts = getTryUmounts(context).toMutableSet()
currentUmounts.add("$path|$mode")
saveTryUmounts(context, currentUmounts)
// 如果开启了开机自启动,更新启动脚本
if (isAutoStartEnabled(context)) {
createStartupScript(context)
}
}
return success
}
/**
* 移除尝试卸载
*/
suspend fun removeTryUmount(context: Context, umountEntry: String): Boolean {
val currentUmounts = getTryUmounts(context).toMutableSet()
currentUmounts.remove(umountEntry)
saveTryUmounts(context, currentUmounts)
// 如果开启了开机自启动,更新启动脚本
if (isAutoStartEnabled(context)) {
createStartupScript(context)
}
val parts = umountEntry.split("|")
val path = if (parts.isNotEmpty()) parts[0] else umountEntry
withContext(Dispatchers.Main) {
Toast.makeText(context, "已移除尝试卸载: $path", Toast.LENGTH_SHORT).show()
}
return true
}
/**
* 运行尝试卸载
*/
suspend fun runTryUmount(context: Context): Boolean {
return executeSusfsCommand(context, "run_try_umount")
}
/**
* 设置Android Data路径
*/
suspend fun setAndroidDataPath(context: Context, path: String): Boolean {
val success = executeSusfsCommand(context, "set_android_data_root_path '$path'")
if (success) {
saveAndroidDataPath(context, path)
// 如果开启了开机自启动,更新启动脚本
if (isAutoStartEnabled(context)) {
createStartupScript(context)
}
}
return success
}
/**
* 设置SD卡路径
*/
suspend fun setSdcardPath(context: Context, path: String): Boolean {
val success = executeSusfsCommand(context, "set_sdcard_root_path '$path'")
if (success) {
saveSdcardPath(context, path)
// 如果开启了开机自启动,更新启动脚本
if (isAutoStartEnabled(context)) {
createStartupScript(context)
}
}
return success
}
/**
* 执行SuSFS命令设置uname
*/
@@ -241,7 +716,7 @@ fi
// 如果开启了开机自启动,更新启动脚本
if (isAutoStartEnabled(context)) {
createStartupScript(unameValue)
createStartupScript(context)
}
withContext(Dispatchers.Main) {
@@ -284,7 +759,8 @@ fi
if (enabled) {
// 启用开机自启动
val lastValue = getLastAppliedValue(context)
if (lastValue == DEFAULT_UNAME) {
if (lastValue == DEFAULT_UNAME && getSusPaths(context).isEmpty() &&
getSusMounts(context).isEmpty() && getTryUmounts(context).isEmpty()) {
withContext(Dispatchers.Main) {
Toast.makeText(
context,
@@ -314,7 +790,7 @@ fi
}
}
val success = createStartupScript(lastValue)
val success = createStartupScript(context)
if (success) {
setAutoStartEnabled(context, true)
withContext(Dispatchers.Main) {

View File

@@ -1090,107 +1090,106 @@ fun MoreSettingsScreen(
onChange = onHideLinkCardChange
)
}
KsuIsValid {
// 高级设置
SettingsCard(
title = stringResource(R.string.advanced_settings)
) {
// SELinux 开关
SwitchSettingItem(
icon = Icons.Filled.Security,
title = stringResource(R.string.selinux),
summary = if (selinuxEnabled)
stringResource(R.string.selinux_enabled) else
stringResource(R.string.selinux_disabled),
checked = selinuxEnabled,
onChange = { enabled ->
val command = if (enabled) "setenforce 1" else "setenforce 0"
Shell.getShell().newJob().add(command).exec().let { result ->
if (result.isSuccess) {
selinuxEnabled = enabled
// 显示成功提示
val message = if (enabled)
context.getString(R.string.selinux_enabled_toast)
else
context.getString(R.string.selinux_disabled_toast)
// 高级设置
SettingsCard(
title = stringResource(R.string.advanced_settings)
) {
// SELinux 开关
KsuIsValid {
SwitchSettingItem(
icon = Icons.Filled.Security,
title = stringResource(R.string.selinux),
summary = if (selinuxEnabled)
stringResource(R.string.selinux_enabled) else
stringResource(R.string.selinux_disabled),
checked = selinuxEnabled,
onChange = { enabled ->
val command = if (enabled) "setenforce 1" else "setenforce 0"
Shell.getShell().newJob().add(command).exec().let { result ->
if (result.isSuccess) {
selinuxEnabled = enabled
// 显示成功提示
val message = if (enabled)
context.getString(R.string.selinux_enabled_toast)
else
context.getString(R.string.selinux_disabled_toast)
Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
} else {
// 显示失败提示
Toast.makeText(
context,
context.getString(R.string.selinux_change_failed),
Toast.LENGTH_SHORT
).show()
}
}
}
)
Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
} else {
// 显示失败提示
// SuSFS 配置(仅在支持时显示存)
if (getSuSFS() == "Supported" && SuSFSManager.isBinaryAvailable(context)) {
SettingItem(
icon = Icons.Default.Settings,
title = stringResource(R.string.susfs_config_setting_title),
subtitle = stringResource(
R.string.susfs_config_setting_summary,
SuSFSManager.getUnameValue(context)
),
onClick = { showSuSFSConfigDialog = true }
)
}
// SuSFS 开关(仅在支持时显示)
val suSFS = getSuSFS()
val isSUS_SU = getSuSFSFeatures()
if (suSFS == "Supported" && isSUS_SU == "CONFIG_KSU_SUSFS_SUS_SU") {
// 默认启用
var isEnabled by rememberSaveable {
mutableStateOf(true)
}
// 在启动时检查状态
LaunchedEffect(Unit) {
// 如果当前模式不是2就强制启用
val currentMode = susfsSUS_SU_Mode()
val wasManuallyDisabled = prefs.getBoolean("enable_sus_su", true)
if (currentMode != "2" && wasManuallyDisabled) {
susfsSUS_SU_2() // 强制切换到模式2
prefs.edit { putBoolean("enable_sus_su", true) }
}
isEnabled = currentMode == "2"
}
SwitchSettingItem(
icon = Icons.Filled.Security,
title = stringResource(id = R.string.settings_susfs_toggle),
summary = stringResource(id = R.string.settings_susfs_toggle_summary),
checked = isEnabled,
onChange = {
if (it) {
// 手动启用
susfsSUS_SU_2()
prefs.edit { putBoolean("enable_sus_su", true) }
Toast.makeText(
context,
context.getString(R.string.selinux_change_failed),
context.getString(R.string.susfs_enabled),
Toast.LENGTH_SHORT
).show()
} else {
// 手动关闭
susfsSUS_SU_0()
prefs.edit { putBoolean("enable_sus_su", false) }
Toast.makeText(
context,
context.getString(R.string.susfs_disabled),
Toast.LENGTH_SHORT
).show()
}
isEnabled = it
}
}
)
}
// SuSFS 配置(仅在支持时显示存)
if (getSuSFS() == "Supported" && SuSFSManager.isBinaryAvailable(context)) {
SettingItem(
icon = Icons.Default.Settings,
title = stringResource(R.string.susfs_config_setting_title),
subtitle = stringResource(
R.string.susfs_config_setting_summary,
SuSFSManager.getUnameValue(context)
),
onClick = { showSuSFSConfigDialog = true }
)
}
// SuSFS 开关(仅在支持时显示)
val suSFS = getSuSFS()
val isSUS_SU = getSuSFSFeatures()
if (suSFS == "Supported" && isSUS_SU == "CONFIG_KSU_SUSFS_SUS_SU") {
// 默认启用
var isEnabled by rememberSaveable {
mutableStateOf(true)
)
}
// 在启动时检查状态
LaunchedEffect(Unit) {
// 如果当前模式不是2就强制启用
val currentMode = susfsSUS_SU_Mode()
val wasManuallyDisabled = prefs.getBoolean("enable_sus_su", true)
if (currentMode != "2" && wasManuallyDisabled) {
susfsSUS_SU_2() // 强制切换到模式2
prefs.edit { putBoolean("enable_sus_su", true) }
}
isEnabled = currentMode == "2"
}
SwitchSettingItem(
icon = Icons.Filled.Security,
title = stringResource(id = R.string.settings_susfs_toggle),
summary = stringResource(id = R.string.settings_susfs_toggle_summary),
checked = isEnabled,
onChange = {
if (it) {
// 手动启用
susfsSUS_SU_2()
prefs.edit { putBoolean("enable_sus_su", true) }
Toast.makeText(
context,
context.getString(R.string.susfs_enabled),
Toast.LENGTH_SHORT
).show()
} else {
// 手动关闭
susfsSUS_SU_0()
prefs.edit { putBoolean("enable_sus_su", false) }
Toast.makeText(
context,
context.getString(R.string.susfs_disabled),
Toast.LENGTH_SHORT
).show()
}
isEnabled = it
}
)
}
}
}

View File

@@ -72,7 +72,7 @@
<string name="failed_to_update_app_profile">为 %s 更新 App Profile 失败</string>
<string name="require_kernel_version" formatted="false">当前 KernelSU 版本 %d 过低,管理器无法正常工作,请将内核 KernelSU 版本升级至 %d 或以上!</string>
<string name="settings_umount_modules_default">默认卸载模块</string>
<string name="settings_umount_modules_default_summary">App Profile 中卸载模块的全局默认值,如果启用,将会为没有设置 Profile 的应用移除所有模块针对系统的修改。</string>
<string name="settings_umount_modules_default_summary">App Profile 中"卸载模块"的全局默认值,如果启用,将会为没有设置 Profile 的应用移除所有模块针对系统的修改。</string>
<string name="settings_susfs_toggle">禁用 kprobe 钩子</string>
<string name="profile_umount_modules_summary">启用该选项后将允许 KernelSU 为本应用还原被模块修改过的文件。</string>
<string name="profile_selinux_domain"></string>
@@ -129,7 +129,7 @@
<string name="settings_restore_stock_image">恢复原厂镜像</string>
<string name="settings_uninstall_temporary_message">临时卸载 KernelSU下次重启后恢复至原始状态。</string>
<string name="settings_uninstall_permanent_message">完全并永久卸载 KernelSURoot 权限和所有模块)。</string>
<string name="settings_restore_stock_image_message">恢复原厂镜像(若存在备份),一般在 OTA 前使用;如果你需要卸载 KernelSU请使用永久卸载</string>
<string name="settings_restore_stock_image_message">恢复原厂镜像(若存在备份),一般在 OTA 前使用;如果你需要卸载 KernelSU请使用"永久卸载"</string>
<string name="flashing">刷写中</string>
<string name="flash_success">刷写完成</string>
<string name="flash_failed">刷写失败</string>
@@ -405,9 +405,9 @@
<string name="susfs_current_value">当前值: %s</string>
<string name="susfs_reset_to_default">重置为默认值</string>
<string name="susfs_apply">应用</string>
<string name="susfs_done">完成</string>
<!-- SuSFS Reset Confirmation -->
<string name="susfs_reset_confirm_title">确认重置</string>
<string name="susfs_reset_confirm_message">确定要将 SuSFS uname 重置为默认值吗?此操作不可撤销。</string>
<string name="susfs_reset_confirm">确认重置</string>
<!-- SuSFS Toast Messages -->
<string name="susfs_binary_not_found">无法找到 ksu_susfs 文件</string>
@@ -420,6 +420,7 @@
<!-- 开机自启动相关 -->
<string name="susfs_autostart_title">开机自启动</string>
<string name="susfs_autostart_description">系统启动时自动应用 uname 配置</string>
<string name="susfs_autostart_requirement">需要配置uname或添加路径后才能启用</string>
<string name="susfs_autostart_enabled">开机自启动已启用</string>
<string name="susfs_autostart_disabled">开机自启动已禁用</string>
<string name="susfs_autostart_enable_failed">启用开机自启动失败</string>
@@ -427,4 +428,80 @@
<string name="susfs_autostart_error">开机自启动配置错误: %s</string>
<string name="susfs_no_config_to_autostart">没有可用的配置进行开机自启动</string>
<string name="susfs_autostart_tis">需要输入非默认值才能启用开机自启动</string>
<!-- SuSFS Tab Titles -->
<string name="susfs_tab_basic_settings">基本设置</string>
<string name="susfs_tab_sus_paths">SUS路径</string>
<string name="susfs_tab_sus_mounts">SUS挂载</string>
<string name="susfs_tab_try_umount">尝试卸载</string>
<string name="susfs_tab_path_settings">路径设置</string>
<string name="susfs_tab_enabled_features">启用功能状态</string>
<!-- SuSFS Dialog Actions -->
<string name="susfs_add">添加</string>
<string name="susfs_delete">删除</string>
<string name="susfs_reset">重置</string>
<string name="susfs_run">运行</string>
<string name="susfs_refresh">刷新</string>
<!-- SuSFS Path Management -->
<string name="susfs_add_sus_path">添加SUS路径</string>
<string name="susfs_add_sus_mount">添加SUS挂载</string>
<string name="susfs_add_try_umount">添加尝试卸载</string>
<string name="susfs_path_label">路径</string>
<string name="susfs_mount_path_label">挂载路径</string>
<string name="susfs_path_placeholder">例如: /system/addon.d</string>
<string name="susfs_sus_paths_management">SUS路径管理</string>
<string name="susfs_sus_mounts_management">SUS挂载管理</string>
<string name="susfs_try_umount_management">尝试卸载管理</string>
<string name="susfs_no_paths_configured">暂无SUS路径配置</string>
<string name="susfs_no_mounts_configured">暂无SUS挂载配置</string>
<string name="susfs_no_umounts_configured">暂无尝试卸载配置</string>
<!-- SuSFS Umount Mode -->
<string name="susfs_umount_mode_label">卸载模式</string>
<string name="susfs_umount_mode_normal">普通卸载 (0)</string>
<string name="susfs_umount_mode_detach">分离卸载 (1)</string>
<string name="susfs_umount_mode_normal_short">普通</string>
<string name="susfs_umount_mode_detach_short">分离</string>
<string name="susfs_umount_mode_display">模式: %1$s (%2$s)</string>
<!-- SuSFS Run Umount -->
<string name="susfs_run_umount_confirm_title">确认运行尝试卸载</string>
<string name="susfs_run_umount_confirm_message">这将立即执行所有已配置的尝试卸载操作,确定要继续吗?</string>
<!-- SuSFS Reset Categories -->
<string name="susfs_reset_paths_title">重置SUS路径</string>
<string name="susfs_reset_paths_message">这将清除所有SUS路径配置确定要继续吗</string>
<string name="susfs_reset_mounts_title">重置SUS挂载</string>
<string name="susfs_reset_mounts_message">这将清除所有SUS挂载配置确定要继续吗</string>
<string name="susfs_reset_umounts_title">重置尝试卸载</string>
<string name="susfs_reset_umounts_message">这将清除所有尝试卸载配置,确定要继续吗?</string>
<!-- SuSFS Path Settings -->
<string name="susfs_path_settings">路径设置</string>
<string name="susfs_android_data_path_label">Android Data路径</string>
<string name="susfs_sdcard_path_label">SD卡路径</string>
<string name="susfs_set_android_data_path">设置Android Data路径</string>
<string name="susfs_set_sdcard_path">设置SD卡路径</string>
<!-- SuSFS Enabled Features -->
<string name="susfs_enabled_features_title">启用功能状态</string>
<string name="susfs_enabled_features_description">显示当前SuSFS启用的功能状态</string>
<string name="susfs_no_features_found">未找到功能状态信息</string>
<string name="susfs_feature_enabled">已启用</string>
<string name="susfs_feature_disabled">已禁用</string>
<!-- Feature Labels -->
<string name="sus_path_feature_label">SUS 路径支持</string>
<string name="sus_mount_feature_label">SUS 挂载支持</string>
<string name="try_umount_feature_label">尝试卸载支持</string>
<string name="spoof_uname_feature_label">欺骗 uname 支持</string>
<string name="spoof_cmdline_feature_label">欺骗 Cmdline/Bootconfig</string>
<string name="open_redirect_feature_label">开放重定向支持</string>
<string name="enable_log_feature_label">日志记录支持</string>
<string name="auto_default_mount_feature_label">自动默认挂载</string>
<string name="auto_bind_mount_feature_label">自动绑定挂载</string>
<string name="auto_try_umount_bind_feature_label">自动尝试卸载绑定挂载</string>
<string name="hide_symbols_feature_label">隐藏 KSU SUSFS 符号</string>
<string name="magic_mount_feature_label">魔法坐骑支持</string>
<string name="overlayfs_auto_kstat_feature_label">OverlayFS 自动内核统计支持</string>
<string name="sus_kstat_feature_label">SUS Kstat Support</string>
<!-- Content Descriptions for Accessibility -->
<string name="susfs_add_button_description">添加新项目</string>
<string name="susfs_run_button_description">运行卸载操作</string>
<string name="susfs_delete_button_description">删除项目</string>
<string name="susfs_reset_section_description">重置此部分</string>
<string name="susfs_refresh_button_description">刷新功能状态</string>
</resources>

View File

@@ -407,9 +407,9 @@
<string name="susfs_current_value">Current value: %s</string>
<string name="susfs_reset_to_default">Reset to Default</string>
<string name="susfs_apply">Apply</string>
<string name="susfs_done">Done</string>
<!-- SuSFS Reset Confirmation -->
<string name="susfs_reset_confirm_title">Confirm Reset</string>
<string name="susfs_reset_confirm_message">Are you sure you want to reset SuSFS uname to default value? This action cannot be undone.</string>
<string name="susfs_reset_confirm">Confirm Reset</string>
<!-- SuSFS Toast Messages -->
<string name="susfs_binary_not_found">Cannot find ksu_susfs file</string>
@@ -420,13 +420,90 @@
<string name="susfs_config_setting_title">SuSFS Configuration</string>
<string name="susfs_config_setting_summary">Configure SuSFS uname value (Current: %s)</string>
<!-- 开机自启动相关 -->
<string name="susfs_autostart_title">boot-up</string>
<string name="susfs_autostart_description">Automatic application of uname configuration at system startup</string>
<string name="susfs_autostart_enabled">Boot Self-Start is enabled</string>
<string name="susfs_autostart_disabled">Boot Self-Start is disabled</string>
<string name="susfs_autostart_enable_failed">Failed to enable boot self-start</string>
<string name="susfs_autostart_disable_failed">Failure to disable boot-up</string>
<string name="susfs_autostart_error">Boot-up misconfiguration: %s</string>
<string name="susfs_no_config_to_autostart">There is no available configuration for boot self-start</string>
<string name="susfs_autostart_tis">Need to enter a non-default value to enable bootstrapping</string>
<string name="susfs_autostart_title">Auto Start</string>
<string name="susfs_autostart_description">Automatically apply uname configuration at system startup</string>
<string name="susfs_autostart_requirement">Need to configure uname or add paths to enable</string>
<string name="susfs_autostart_enabled">Auto Start enabled</string>
<string name="susfs_autostart_disabled">Auto Start disabled</string>
<string name="susfs_autostart_enable_failed">Failed to enable auto start</string>
<string name="susfs_autostart_disable_failed">Failed to disable auto start</string>
<string name="susfs_autostart_error">Auto start configuration error: %s</string>
<string name="susfs_no_config_to_autostart">No available configuration for auto start</string>
<string name="susfs_autostart_tis">Need to enter a non-default value to enable auto start</string>
<!-- SuSFS Tab Titles -->
<string name="susfs_tab_basic_settings">Basic Settings</string>
<string name="susfs_tab_sus_paths">SUS Paths</string>
<string name="susfs_tab_sus_mounts">SUS Mounts</string>
<string name="susfs_tab_try_umount">Try Umount</string>
<string name="susfs_tab_path_settings">Path Settings</string>
<string name="susfs_tab_enabled_features">Enabled Features Status</string>
<!-- SuSFS Dialog Actions -->
<string name="susfs_add">Add</string>
<string name="susfs_delete">Delete</string>
<string name="susfs_reset">Reset</string>
<string name="susfs_run">Run</string>
<string name="susfs_refresh">Refresh</string>
<!-- SuSFS Path Management -->
<string name="susfs_add_sus_path">Add SUS Path</string>
<string name="susfs_add_sus_mount">Add SUS Mount</string>
<string name="susfs_add_try_umount">Add Try Umount</string>
<string name="susfs_path_label">Path</string>
<string name="susfs_mount_path_label">Mount Path</string>
<string name="susfs_path_placeholder">e.g.: /system/addon.d</string>
<string name="susfs_sus_paths_management">SUS Paths Management</string>
<string name="susfs_sus_mounts_management">SUS Mounts Management</string>
<string name="susfs_try_umount_management">Try Umount Management</string>
<string name="susfs_no_paths_configured">No SUS paths configured</string>
<string name="susfs_no_mounts_configured">No SUS mounts configured</string>
<string name="susfs_no_umounts_configured">No try umount configured</string>
<!-- SuSFS Umount Mode -->
<string name="susfs_umount_mode_label">Umount Mode</string>
<string name="susfs_umount_mode_normal">Normal Umount (0)</string>
<string name="susfs_umount_mode_detach">Detach Umount (1)</string>
<string name="susfs_umount_mode_normal_short">Normal</string>
<string name="susfs_umount_mode_detach_short">Detach</string>
<string name="susfs_umount_mode_display">Mode: %1$s (%2$s)</string>
<!-- SuSFS Run Umount -->
<string name="susfs_run_umount_confirm_title">Confirm Run Try Umount</string>
<string name="susfs_run_umount_confirm_message">This will immediately execute all configured try umount operations. Are you sure you want to continue?</string>
<!-- SuSFS Reset Categories -->
<string name="susfs_reset_paths_title">Reset SUS Paths</string>
<string name="susfs_reset_paths_message">This will clear all SUS path configurations. Are you sure you want to continue?</string>
<string name="susfs_reset_mounts_title">Reset SUS Mounts</string>
<string name="susfs_reset_mounts_message">This will clear all SUS mount configurations. Are you sure you want to continue?</string>
<string name="susfs_reset_umounts_title">Reset Try Umount</string>
<string name="susfs_reset_umounts_message">This will clear all try umount configurations. Are you sure you want to continue?</string>
<!-- SuSFS Path Settings -->
<string name="susfs_path_settings">Path Settings</string>
<string name="susfs_android_data_path_label">Android Data Path</string>
<string name="susfs_sdcard_path_label">SD Card Path</string>
<string name="susfs_set_android_data_path">Set Android Data Path</string>
<string name="susfs_set_sdcard_path">Set SD Card Path</string>
<!-- SuSFS Enabled Features -->
<string name="susfs_enabled_features_title">Enabled Features Status</string>
<string name="susfs_enabled_features_description">Display current SuSFS enabled features status</string>
<string name="susfs_no_features_found">No feature status information found</string>
<string name="susfs_feature_enabled">Enabled</string>
<string name="susfs_feature_disabled">Disabled</string>
<!-- Feature Labels -->
<string name="sus_path_feature_label">SUS Path Support</string>
<string name="sus_mount_feature_label">SUS Mount Support</string>
<string name="try_umount_feature_label">Try Umount Support</string>
<string name="spoof_uname_feature_label">Spoof uname Support</string>
<string name="spoof_cmdline_feature_label">Spoof Cmdline/Bootconfig</string>
<string name="open_redirect_feature_label">Open Redirect Support</string>
<string name="enable_log_feature_label">Logging Support</string>
<string name="auto_default_mount_feature_label">Auto Default Mount</string>
<string name="auto_bind_mount_feature_label">Auto Bind Mount</string>
<string name="auto_try_umount_bind_feature_label">Auto Try Umount Bind Mount</string>
<string name="hide_symbols_feature_label">Hide KSU SUSFS Symbols</string>
<string name="magic_mount_feature_label">Magic Mount Support</string>
<string name="overlayfs_auto_kstat_feature_label">OverlayFS Auto Kernel Stat Support</string>
<string name="sus_kstat_feature_label">SUS Kstat Support</string>
<!-- Content Descriptions for Accessibility -->
<string name="susfs_add_button_description">Add new item</string>
<string name="susfs_run_button_description">Run umount operations</string>
<string name="susfs_delete_button_description">Delete item</string>
<string name="susfs_reset_section_description">Reset this section</string>
<string name="susfs_refresh_button_description">Refresh feature status</string>
</resources>