manager: Optimize susfs management,

- solve some problems caused by new versions not taking effect
This commit is contained in:
ShirkNeko
2025-06-26 14:10:50 +08:00
parent 9393459b27
commit cfee357ed1
12 changed files with 227 additions and 193 deletions

View File

@@ -77,7 +77,7 @@ fun AddPathDialog(
enabled = newPath.isNotBlank() && !isLoading, enabled = newPath.isNotBlank() && !isLoading,
shape = RoundedCornerShape(8.dp) shape = RoundedCornerShape(8.dp)
) { ) {
Text(stringResource(R.string.susfs_add)) Text(stringResource(R.string.add))
} }
}, },
dismissButton = { dismissButton = {
@@ -186,7 +186,7 @@ fun AddTryUmountDialog(
enabled = newUmountPath.isNotBlank() && !isLoading, enabled = newUmountPath.isNotBlank() && !isLoading,
shape = RoundedCornerShape(8.dp) shape = RoundedCornerShape(8.dp)
) { ) {
Text(stringResource(R.string.susfs_add)) Text(stringResource(R.string.add))
} }
}, },
dismissButton = { dismissButton = {
@@ -431,7 +431,7 @@ fun AddKstatStaticallyDialog(
enabled = newKstatPath.isNotBlank() && !isLoading, enabled = newKstatPath.isNotBlank() && !isLoading,
shape = RoundedCornerShape(8.dp) shape = RoundedCornerShape(8.dp)
) { ) {
Text("添加") Text(stringResource(R.string.add))
} }
}, },
dismissButton = { dismissButton = {

View File

@@ -97,7 +97,7 @@ fun SusPathsContent(
modifier = Modifier.size(24.dp) modifier = Modifier.size(24.dp)
) )
Spacer(modifier = Modifier.width(8.dp)) Spacer(modifier = Modifier.width(8.dp))
Text(text = stringResource(R.string.susfs_add)) Text(text = stringResource(R.string.add))
} }
} }
} }
@@ -172,7 +172,7 @@ fun SusMountsContent(
modifier = Modifier.size(24.dp) modifier = Modifier.size(24.dp)
) )
Spacer(modifier = Modifier.width(8.dp)) Spacer(modifier = Modifier.width(8.dp))
Text(text = stringResource(R.string.susfs_add)) Text(text = stringResource(R.string.add))
} }
} }
} }
@@ -245,7 +245,7 @@ fun TryUmountContent(
modifier = Modifier.size(24.dp) modifier = Modifier.size(24.dp)
) )
Spacer(modifier = Modifier.width(8.dp)) Spacer(modifier = Modifier.width(8.dp))
Text(text = stringResource(R.string.susfs_add)) Text(text = stringResource(R.string.add))
} }
if (tryUmounts.isNotEmpty()) { if (tryUmounts.isNotEmpty()) {
@@ -403,7 +403,7 @@ fun KstatConfigContent(
modifier = Modifier.size(24.dp) modifier = Modifier.size(24.dp)
) )
Spacer(modifier = Modifier.width(8.dp)) Spacer(modifier = Modifier.width(8.dp))
Text(text = stringResource(R.string.susfs_add)) Text(text = stringResource(R.string.add))
} }
Button( Button(
@@ -419,7 +419,7 @@ fun KstatConfigContent(
modifier = Modifier.size(24.dp) modifier = Modifier.size(24.dp)
) )
Spacer(modifier = Modifier.width(8.dp)) Spacer(modifier = Modifier.width(8.dp))
Text(text = stringResource(R.string.susfs_add)) Text(text = stringResource(R.string.add))
} }
} }
} }

View File

@@ -36,13 +36,14 @@ object SuSFSManager {
private const val KEY_KSTAT_CONFIGS = "kstat_configs" private const val KEY_KSTAT_CONFIGS = "kstat_configs"
private const val KEY_ADD_KSTAT_PATHS = "add_kstat_paths" private const val KEY_ADD_KSTAT_PATHS = "add_kstat_paths"
private const val KEY_HIDE_SUS_MOUNTS_FOR_ALL_PROCS = "hide_sus_mounts_for_all_procs" private const val KEY_HIDE_SUS_MOUNTS_FOR_ALL_PROCS = "hide_sus_mounts_for_all_procs"
// 常量 // 常量
private const val SUSFS_BINARY_BASE_NAME = "ksu_susfs" private const val SUSFS_BINARY_BASE_NAME = "ksu_susfs"
private const val DEFAULT_UNAME = "default" private const val DEFAULT_UNAME = "default"
private const val DEFAULT_BUILD_TIME = "default" private const val DEFAULT_BUILD_TIME = "default"
private const val MODULE_ID = "susfs_manager" private const val MODULE_ID = "susfs_manager"
private const val MODULE_PATH = "/data/adb/modules/$MODULE_ID" private const val MODULE_PATH = "/data/adb/modules/$MODULE_ID"
private const val MIN_VERSION_FOR_HIDE_MOUNT = "1.5.8"
data class SlotInfo(val slotName: String, val uname: String, val buildTime: String) data class SlotInfo(val slotName: String, val uname: String, val buildTime: String)
data class CommandResult(val isSuccess: Boolean, val output: String, val errorOutput: String = "") data class CommandResult(val isSuccess: Boolean, val output: String, val errorOutput: String = "")
@@ -53,13 +54,46 @@ object SuSFSManager {
val canConfigure: Boolean = false val canConfigure: Boolean = false
) )
// 命令执行 /**
* 模块配置数据类
*/
data class ModuleConfig(
val targetPath: String,
val unameValue: String,
val buildTimeValue: String,
val executeInPostFsData: Boolean,
val susPaths: Set<String>,
val susMounts: Set<String>,
val tryUmounts: Set<String>,
val androidDataPath: String,
val sdcardPath: String,
val enableLog: Boolean,
val kstatConfigs: Set<String>,
val addKstatPaths: Set<String>,
val hideSusMountsForAllProcs: Boolean,
val support158: Boolean
) {
/**
* 检查是否有需要自启动的配置
*/
fun hasAutoStartConfig(): Boolean {
return unameValue != DEFAULT_UNAME ||
buildTimeValue != DEFAULT_BUILD_TIME ||
susPaths.isNotEmpty() ||
susMounts.isNotEmpty() ||
tryUmounts.isNotEmpty() ||
kstatConfigs.isNotEmpty() ||
addKstatPaths.isNotEmpty()
}
}
// 基础工具方法
private fun getPrefs(context: Context): SharedPreferences = private fun getPrefs(context: Context): SharedPreferences =
context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE) context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
private fun getSuSFSVersionUse(): String = try { private fun getSuSFSVersionUse(): String = try {
getSuSFSVersion() getSuSFSVersion()
} catch (_: Exception) { "1.5.8" } } catch (_: Exception) { MIN_VERSION_FOR_HIDE_MOUNT }
private fun getSuSFSBinaryName(): String = "${SUSFS_BINARY_BASE_NAME}_${getSuSFSVersionUse().removePrefix("v")}" private fun getSuSFSBinaryName(): String = "${SUSFS_BINARY_BASE_NAME}_${getSuSFSVersionUse().removePrefix("v")}"
@@ -78,7 +112,9 @@ object SuSFSManager {
return CommandResult(result.isSuccess, result.out.joinToString("\n"), result.err.joinToString("\n")) return CommandResult(result.isSuccess, result.out.joinToString("\n"), result.err.joinToString("\n"))
} }
// 版本比较 /**
* 版本比较方法
*/
private fun compareVersions(version1: String, version2: String): Int { private fun compareVersions(version1: String, version2: String): Int {
val v1Parts = version1.removePrefix("v").split(".").map { it.toIntOrNull() ?: 0 } val v1Parts = version1.removePrefix("v").split(".").map { it.toIntOrNull() ?: 0 }
val v2Parts = version2.removePrefix("v").split(".").map { it.toIntOrNull() ?: 0 } val v2Parts = version2.removePrefix("v").split(".").map { it.toIntOrNull() ?: 0 }
@@ -97,16 +133,39 @@ object SuSFSManager {
return 0 return 0
} }
// 检查当前SuSFS版本是否支持SUS挂载隐藏控制功能 /**
* 版本检查方法
*/
fun isSusVersion_1_5_8(): Boolean { fun isSusVersion_1_5_8(): Boolean {
return try { return try {
val currentVersion = getSuSFSVersion() val currentVersion = getSuSFSVersion()
compareVersions(currentVersion, "1.5.8") >= 0 compareVersions(currentVersion, MIN_VERSION_FOR_HIDE_MOUNT) >= 0
} catch (_: Exception) { } catch (_: Exception) {
true true // 默认支持新功能
} }
} }
/**
* 获取当前模块配置
*/
private fun getCurrentModuleConfig(context: Context): ModuleConfig {
return ModuleConfig(
targetPath = getSuSFSTargetPath(),
unameValue = getUnameValue(context),
buildTimeValue = getBuildTimeValue(context),
executeInPostFsData = getExecuteInPostFsData(context),
susPaths = getSusPaths(context),
susMounts = getSusMounts(context),
tryUmounts = getTryUmounts(context),
androidDataPath = getAndroidDataPath(context),
sdcardPath = getSdcardPath(context),
enableLog = getEnableLogState(context),
kstatConfigs = getKstatConfigs(context),
addKstatPaths = getAddKstatPaths(context),
hideSusMountsForAllProcs = getHideSusMountsForAllProcs(context),
support158 = isSusVersion_1_5_8()
)
}
// 配置存取方法 // 配置存取方法
fun saveUnameValue(context: Context, value: String) = fun saveUnameValue(context: Context, value: String) =
@@ -143,8 +202,7 @@ object SuSFSManager {
getPrefs(context).edit { putBoolean(KEY_EXECUTE_IN_POST_FS_DATA, executeInPostFsData) } getPrefs(context).edit { putBoolean(KEY_EXECUTE_IN_POST_FS_DATA, executeInPostFsData) }
if (isAutoStartEnabled(context)) { if (isAutoStartEnabled(context)) {
kotlinx.coroutines.CoroutineScope(Dispatchers.Default).launch { kotlinx.coroutines.CoroutineScope(Dispatchers.Default).launch {
removeMagiskModule() updateMagiskModule(context)
createMagiskModule(context)
} }
} }
} }
@@ -203,8 +261,6 @@ object SuSFSManager {
fun getSdcardPath(context: Context): String = fun getSdcardPath(context: Context): String =
getPrefs(context).getString(KEY_SDCARD_PATH, "/sdcard") ?: "/sdcard" getPrefs(context).getString(KEY_SDCARD_PATH, "/sdcard") ?: "/sdcard"
// 槽位信息获取 // 槽位信息获取
suspend fun getCurrentSlotInfo(): List<SlotInfo> = withContext(Dispatchers.IO) { suspend fun getCurrentSlotInfo(): List<SlotInfo> = withContext(Dispatchers.IO) {
try { try {
@@ -310,17 +366,19 @@ object SuSFSManager {
Toast.makeText(context, message, Toast.LENGTH_SHORT).show() Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
} }
private inline fun <reified T> Map<String, Any?>.getSetSafe(key: String): Set<T> { /**
return when (val value = this[key]) { * 模块管理
is Set<*> -> value.filterIsInstance<T>().toSet() */
else -> emptySet() private suspend fun updateMagiskModule(context: Context): Boolean {
} return removeMagiskModule() && createMagiskModule(context)
} }
// 模块管理 /**
* 模块创建方法
*/
private suspend fun createMagiskModule(context: Context): Boolean = withContext(Dispatchers.IO) { private suspend fun createMagiskModule(context: Context): Boolean = withContext(Dispatchers.IO) {
try { try {
val targetPath = getSuSFSTargetPath() val config = getCurrentModuleConfig(context)
// 创建模块目录 // 创建模块目录
if (!runCmdWithResult("mkdir -p $MODULE_PATH").isSuccess) return@withContext false if (!runCmdWithResult("mkdir -p $MODULE_PATH").isSuccess) return@withContext false
@@ -329,44 +387,9 @@ object SuSFSManager {
val moduleProp = ScriptGenerator.generateModuleProp(MODULE_ID) val moduleProp = ScriptGenerator.generateModuleProp(MODULE_ID)
if (!runCmdWithResult("cat > $MODULE_PATH/module.prop << 'EOF'\n$moduleProp\nEOF").isSuccess) return@withContext false if (!runCmdWithResult("cat > $MODULE_PATH/module.prop << 'EOF'\n$moduleProp\nEOF").isSuccess) return@withContext false
// 获取配置 // 生成并创建所有脚本文件
val config = mapOf( val scripts = ScriptGenerator.generateAllScripts(config)
"unameValue" to getUnameValue(context),
"buildTimeValue" to getBuildTimeValue(context),
"executeInPostFsData" to getExecuteInPostFsData(context),
"susPaths" to getSusPaths(context),
"susMounts" to getSusMounts(context),
"tryUmounts" to getTryUmounts(context),
"androidDataPath" to getAndroidDataPath(context),
"sdcardPath" to getSdcardPath(context),
"enableLog" to getEnableLogState(context),
"kstatConfigs" to getKstatConfigs(context),
"addKstatPaths" to getAddKstatPaths(context),
"hideSusMountsForAllProcs" to getHideSusMountsForAllProcs(context)
)
// 生成脚本
val scripts = mapOf(
"service.sh" to ScriptGenerator.generateServiceScript(
targetPath, config["unameValue"] as String, config["buildTimeValue"] as String,
config.getSetSafe<String>("susPaths"), config["enableLog"] as Boolean,
config["executeInPostFsData"] as Boolean, config.getSetSafe<String>("kstatConfigs"),
config.getSetSafe<String>("addKstatPaths")
),
"post-fs-data.sh" to ScriptGenerator.generatePostFsDataScript(
targetPath, config["unameValue"] as String, config["buildTimeValue"] as String,
config["executeInPostFsData"] as Boolean, config["androidDataPath"] as String,
config["sdcardPath"] as String
),
"post-mount.sh" to ScriptGenerator.generatePostMountScript(
targetPath, config.getSetSafe<String>("susMounts"), config.getSetSafe<String>("tryUmounts")
),
"boot-completed.sh" to ScriptGenerator.generateBootCompletedScript(
targetPath, config["hideSusMountsForAllProcs"] as Boolean
)
)
// 创建脚本文件
scripts.all { (filename, content) -> scripts.all { (filename, content) ->
runCmdWithResult("cat > $MODULE_PATH/$filename << 'EOF'\n$content\nEOF").isSuccess && runCmdWithResult("cat > $MODULE_PATH/$filename << 'EOF'\n$content\nEOF").isSuccess &&
runCmdWithResult("chmod 755 $MODULE_PATH/$filename").isSuccess runCmdWithResult("chmod 755 $MODULE_PATH/$filename").isSuccess
@@ -386,7 +409,6 @@ object SuSFSManager {
} }
} }
// 功能状态获取 // 功能状态获取
suspend fun getEnabledFeatures(context: Context): List<EnabledFeature> = withContext(Dispatchers.IO) { suspend fun getEnabledFeatures(context: Context): List<EnabledFeature> = withContext(Dispatchers.IO) {
try { try {
@@ -430,7 +452,6 @@ object SuSFSManager {
}.sortedBy { it.name } }.sortedBy { it.name }
} }
private fun parseEnabledFeaturesFromStatus(context: Context, status: Natives.SusfsFeatureStatus): List<EnabledFeature> { private fun parseEnabledFeaturesFromStatus(context: Context, status: Natives.SusfsFeatureStatus): List<EnabledFeature> {
val featureList = listOf( val featureList = listOf(
Triple("status_sus_path", context.getString(R.string.sus_path_feature_label), status.statusSusPath), Triple("status_sus_path", context.getString(R.string.sus_path_feature_label), status.statusSusPath),
@@ -461,7 +482,7 @@ object SuSFSManager {
val success = executeSusfsCommand(context, "enable_log ${if (enabled) 1 else 0}") val success = executeSusfsCommand(context, "enable_log ${if (enabled) 1 else 0}")
if (success) { if (success) {
saveEnableLogState(context, enabled) saveEnableLogState(context, enabled)
if (isAutoStartEnabled(context)) createMagiskModule(context) if (isAutoStartEnabled(context)) updateMagiskModule(context)
showToast(context, if (enabled) context.getString(R.string.susfs_log_enabled) else context.getString(R.string.susfs_log_disabled)) showToast(context, if (enabled) context.getString(R.string.susfs_log_enabled) else context.getString(R.string.susfs_log_disabled))
} }
return success return success
@@ -476,7 +497,7 @@ object SuSFSManager {
val success = executeSusfsCommand(context, "hide_sus_mnts_for_all_procs ${if (hideForAll) 1 else 0}") val success = executeSusfsCommand(context, "hide_sus_mnts_for_all_procs ${if (hideForAll) 1 else 0}")
if (success) { if (success) {
saveHideSusMountsForAllProcs(context, hideForAll) saveHideSusMountsForAllProcs(context, hideForAll)
if (isAutoStartEnabled(context)) createMagiskModule(context) if (isAutoStartEnabled(context)) updateMagiskModule(context)
showToast(context, if (hideForAll) showToast(context, if (hideForAll)
context.getString(R.string.susfs_hide_mounts_all_enabled) context.getString(R.string.susfs_hide_mounts_all_enabled)
else else
@@ -493,7 +514,7 @@ object SuSFSManager {
if (success) { if (success) {
saveUnameValue(context, unameValue) saveUnameValue(context, unameValue)
saveBuildTimeValue(context, buildTimeValue) saveBuildTimeValue(context, buildTimeValue)
if (isAutoStartEnabled(context)) createMagiskModule(context) if (isAutoStartEnabled(context)) updateMagiskModule(context)
showToast(context, context.getString(R.string.susfs_uname_set_success, unameValue, buildTimeValue)) showToast(context, context.getString(R.string.susfs_uname_set_success, unameValue, buildTimeValue))
} }
return success return success
@@ -502,12 +523,37 @@ object SuSFSManager {
// 添加SUS路径 // 添加SUS路径
@SuppressLint("StringFormatInvalid") @SuppressLint("StringFormatInvalid")
suspend fun addSusPath(context: Context, path: String): Boolean { suspend fun addSusPath(context: Context, path: String): Boolean {
// 如果是1.5.8版本,先设置路径配置
if (isSusVersion_1_5_8()) {
// 获取当前配置的路径,如果没有配置则使用默认值
val androidDataPath = getAndroidDataPath(context)
val sdcardPath = getSdcardPath(context)
// 先设置Android Data路径
val androidDataSuccess = executeSusfsCommand(context, "set_android_data_root_path '$androidDataPath'")
if (androidDataSuccess) {
showToast(context, context.getString(R.string.susfs_android_data_path_set, androidDataPath))
}
// 再设置SD卡路径
val sdcardSuccess = executeSusfsCommand(context, "set_sdcard_root_path '$sdcardPath'")
if (sdcardSuccess) {
showToast(context, context.getString(R.string.susfs_sdcard_path_set, sdcardPath))
}
// 如果路径设置失败,记录但不阻止继续执行
if (!androidDataSuccess || !sdcardSuccess) {
showToast(context, context.getString(R.string.susfs_path_setup_warning))
}
}
// 执行添加SUS路径命令
val result = executeSusfsCommandWithOutput(context, "add_sus_path '$path'") val result = executeSusfsCommandWithOutput(context, "add_sus_path '$path'")
val isActuallySuccessful = result.isSuccess && !result.output.contains("not found, skip adding") val isActuallySuccessful = result.isSuccess && !result.output.contains("not found, skip adding")
if (isActuallySuccessful) { if (isActuallySuccessful) {
saveSusPaths(context, getSusPaths(context) + path) saveSusPaths(context, getSusPaths(context) + path)
if (isAutoStartEnabled(context)) createMagiskModule(context) if (isAutoStartEnabled(context)) updateMagiskModule(context)
showToast(context, context.getString(R.string.susfs_sus_path_added_success, path)) showToast(context, context.getString(R.string.susfs_sus_path_added_success, path))
} else { } else {
val errorMessage = if (result.output.contains("not found, skip adding")) { val errorMessage = if (result.output.contains("not found, skip adding")) {
@@ -522,7 +568,7 @@ object SuSFSManager {
suspend fun removeSusPath(context: Context, path: String): Boolean { suspend fun removeSusPath(context: Context, path: String): Boolean {
saveSusPaths(context, getSusPaths(context) - path) saveSusPaths(context, getSusPaths(context) - path)
if (isAutoStartEnabled(context)) createMagiskModule(context) if (isAutoStartEnabled(context)) updateMagiskModule(context)
showToast(context, "SUS path removed: $path") showToast(context, "SUS path removed: $path")
return true return true
} }
@@ -532,14 +578,14 @@ object SuSFSManager {
val success = executeSusfsCommand(context, "add_sus_mount '$mount'") val success = executeSusfsCommand(context, "add_sus_mount '$mount'")
if (success) { if (success) {
saveSusMounts(context, getSusMounts(context) + mount) saveSusMounts(context, getSusMounts(context) + mount)
if (isAutoStartEnabled(context)) createMagiskModule(context) if (isAutoStartEnabled(context)) updateMagiskModule(context)
} }
return success return success
} }
suspend fun removeSusMount(context: Context, mount: String): Boolean { suspend fun removeSusMount(context: Context, mount: String): Boolean {
saveSusMounts(context, getSusMounts(context) - mount) saveSusMounts(context, getSusMounts(context) - mount)
if (isAutoStartEnabled(context)) createMagiskModule(context) if (isAutoStartEnabled(context)) updateMagiskModule(context)
showToast(context, "Removed SUS mount: $mount") showToast(context, "Removed SUS mount: $mount")
return true return true
} }
@@ -548,7 +594,7 @@ object SuSFSManager {
suspend fun addTryUmount(context: Context, path: String, mode: Int): Boolean { suspend fun addTryUmount(context: Context, path: String, mode: Int): Boolean {
val commandSuccess = executeSusfsCommand(context, "add_try_umount '$path' $mode") val commandSuccess = executeSusfsCommand(context, "add_try_umount '$path' $mode")
saveTryUmounts(context, getTryUmounts(context) + "$path|$mode") saveTryUmounts(context, getTryUmounts(context) + "$path|$mode")
if (isAutoStartEnabled(context)) createMagiskModule(context) if (isAutoStartEnabled(context)) updateMagiskModule(context)
showToast(context, if (commandSuccess) { showToast(context, if (commandSuccess) {
context.getString(R.string.susfs_try_umount_added_success, path) context.getString(R.string.susfs_try_umount_added_success, path)
@@ -560,7 +606,7 @@ object SuSFSManager {
suspend fun removeTryUmount(context: Context, umountEntry: String): Boolean { suspend fun removeTryUmount(context: Context, umountEntry: String): Boolean {
saveTryUmounts(context, getTryUmounts(context) - umountEntry) saveTryUmounts(context, getTryUmounts(context) - umountEntry)
if (isAutoStartEnabled(context)) createMagiskModule(context) if (isAutoStartEnabled(context)) updateMagiskModule(context)
val path = umountEntry.split("|").firstOrNull() ?: umountEntry val path = umountEntry.split("|").firstOrNull() ?: umountEntry
showToast(context, "Removed Try to uninstall: $path") showToast(context, "Removed Try to uninstall: $path")
return true return true
@@ -577,7 +623,7 @@ object SuSFSManager {
if (success) { if (success) {
val configEntry = "$path|$ino|$dev|$nlink|$size|$atime|$atimeNsec|$mtime|$mtimeNsec|$ctime|$ctimeNsec|$blocks|$blksize" val configEntry = "$path|$ino|$dev|$nlink|$size|$atime|$atimeNsec|$mtime|$mtimeNsec|$ctime|$ctimeNsec|$blocks|$blksize"
saveKstatConfigs(context, getKstatConfigs(context) + configEntry) saveKstatConfigs(context, getKstatConfigs(context) + configEntry)
if (isAutoStartEnabled(context)) createMagiskModule(context) if (isAutoStartEnabled(context)) updateMagiskModule(context)
showToast(context, context.getString(R.string.kstat_static_config_added, path)) showToast(context, context.getString(R.string.kstat_static_config_added, path))
} }
return success return success
@@ -585,7 +631,7 @@ object SuSFSManager {
suspend fun removeKstatConfig(context: Context, config: String): Boolean { suspend fun removeKstatConfig(context: Context, config: String): Boolean {
saveKstatConfigs(context, getKstatConfigs(context) - config) saveKstatConfigs(context, getKstatConfigs(context) - config)
if (isAutoStartEnabled(context)) createMagiskModule(context) if (isAutoStartEnabled(context)) updateMagiskModule(context)
val path = config.split("|").firstOrNull() ?: config val path = config.split("|").firstOrNull() ?: config
showToast(context, context.getString(R.string.kstat_config_removed, path)) showToast(context, context.getString(R.string.kstat_config_removed, path))
return true return true
@@ -596,7 +642,7 @@ object SuSFSManager {
val success = executeSusfsCommand(context, "add_sus_kstat '$path'") val success = executeSusfsCommand(context, "add_sus_kstat '$path'")
if (success) { if (success) {
saveAddKstatPaths(context, getAddKstatPaths(context) + path) saveAddKstatPaths(context, getAddKstatPaths(context) + path)
if (isAutoStartEnabled(context)) createMagiskModule(context) if (isAutoStartEnabled(context)) updateMagiskModule(context)
showToast(context, context.getString(R.string.kstat_path_added, path)) showToast(context, context.getString(R.string.kstat_path_added, path))
} }
return success return success
@@ -604,7 +650,7 @@ object SuSFSManager {
suspend fun removeAddKstat(context: Context, path: String): Boolean { suspend fun removeAddKstat(context: Context, path: String): Boolean {
saveAddKstatPaths(context, getAddKstatPaths(context) - path) saveAddKstatPaths(context, getAddKstatPaths(context) - path)
if (isAutoStartEnabled(context)) createMagiskModule(context) if (isAutoStartEnabled(context)) updateMagiskModule(context)
showToast(context, context.getString(R.string.kstat_path_removed, path)) showToast(context, context.getString(R.string.kstat_path_removed, path))
return true return true
} }
@@ -623,16 +669,14 @@ object SuSFSManager {
return success return success
} }
// 设置Android数据路径和SD卡路径 // 设置Android数据路径
suspend fun setAndroidDataPath(context: Context, path: String): Boolean { suspend fun setAndroidDataPath(context: Context, path: String): Boolean {
val success = executeSusfsCommand(context, "set_android_data_root_path '$path'") val success = executeSusfsCommand(context, "set_android_data_root_path '$path'")
if (success) { if (success) {
saveAndroidDataPath(context, path) saveAndroidDataPath(context, path)
// 如果开机自启动已启用,立即更新模块脚本
if (isAutoStartEnabled(context)) { if (isAutoStartEnabled(context)) {
kotlinx.coroutines.CoroutineScope(Dispatchers.Default).launch { kotlinx.coroutines.CoroutineScope(Dispatchers.Default).launch {
removeMagiskModule() updateMagiskModule(context)
createMagiskModule(context)
} }
} }
} }
@@ -644,29 +688,28 @@ object SuSFSManager {
val success = executeSusfsCommand(context, "set_sdcard_root_path '$path'") val success = executeSusfsCommand(context, "set_sdcard_root_path '$path'")
if (success) { if (success) {
saveSdcardPath(context, path) saveSdcardPath(context, path)
// 如果开机自启动已启用,立即更新模块脚本
if (isAutoStartEnabled(context)) { if (isAutoStartEnabled(context)) {
kotlinx.coroutines.CoroutineScope(Dispatchers.Default).launch { kotlinx.coroutines.CoroutineScope(Dispatchers.Default).launch {
removeMagiskModule() updateMagiskModule(context)
createMagiskModule(context)
} }
} }
} }
return success return success
} }
/**
* 自启动配置检查
*/
fun hasConfigurationForAutoStart(context: Context): Boolean { fun hasConfigurationForAutoStart(context: Context): Boolean {
val enabledFeatures = runBlocking { getEnabledFeatures(context) } val config = getCurrentModuleConfig(context)
return getUnameValue(context) != DEFAULT_UNAME || return config.hasAutoStartConfig() || runBlocking {
getBuildTimeValue(context) != DEFAULT_BUILD_TIME || getEnabledFeatures(context).any { it.isEnabled }
getSusPaths(context).isNotEmpty() || }
getSusMounts(context).isNotEmpty() ||
getTryUmounts(context).isNotEmpty() ||
getKstatConfigs(context).isNotEmpty() ||
getAddKstatPaths(context).isNotEmpty() ||
enabledFeatures.any { it.isEnabled }
} }
/**
* 自启动配置方法
*/
suspend fun configureAutoStart(context: Context, enabled: Boolean): Boolean = withContext(Dispatchers.IO) { suspend fun configureAutoStart(context: Context, enabled: Boolean): Boolean = withContext(Dispatchers.IO) {
try { try {
if (enabled) { if (enabled) {

View File

@@ -9,14 +9,22 @@ import android.annotation.SuppressLint
object ScriptGenerator { object ScriptGenerator {
// 常量定义 // 常量定义
@SuppressLint("SdCardPath")
private const val DEFAULT_ANDROID_DATA_PATH = "/sdcard/Android/data"
@SuppressLint("SdCardPath")
private const val DEFAULT_SDCARD_PATH = "/sdcard"
private const val DEFAULT_UNAME = "default" private const val DEFAULT_UNAME = "default"
private const val DEFAULT_BUILD_TIME = "default" private const val DEFAULT_BUILD_TIME = "default"
private const val LOG_DIR = "/data/adb/ksu/log" private const val LOG_DIR = "/data/adb/ksu/log"
/**
* 生成所有脚本文件
*/
fun generateAllScripts(config: SuSFSManager.ModuleConfig): Map<String, String> {
return mapOf(
"service.sh" to generateServiceScript(config),
"post-fs-data.sh" to generatePostFsDataScript(config),
"post-mount.sh" to generatePostMountScript(config),
"boot-completed.sh" to generateBootCompletedScript(config)
)
}
// 日志相关的通用脚本片段 // 日志相关的通用脚本片段
private fun generateLogSetup(logFileName: String): String = """ private fun generateLogSetup(logFileName: String): String = """
# 日志目录 # 日志目录
@@ -45,17 +53,7 @@ object ScriptGenerator {
/** /**
* 生成service.sh脚本内容 * 生成service.sh脚本内容
*/ */
@SuppressLint("SdCardPath") private fun generateServiceScript(config: SuSFSManager.ModuleConfig): String {
fun generateServiceScript(
targetPath: String,
unameValue: String,
buildTimeValue: String,
susPaths: Set<String>,
enableLog: Boolean,
executeInPostFsData: Boolean = false,
kstatConfigs: Set<String> = emptySet(),
addKstatPaths: Set<String> = emptySet()
): String {
return buildString { return buildString {
appendLine("#!/system/bin/sh") appendLine("#!/system/bin/sh")
appendLine("# SuSFS Service Script") appendLine("# SuSFS Service Script")
@@ -63,21 +61,25 @@ object ScriptGenerator {
appendLine() appendLine()
appendLine(generateLogSetup("susfs_service.log")) appendLine(generateLogSetup("susfs_service.log"))
appendLine() appendLine()
appendLine(generateBinaryCheck(targetPath)) appendLine(generateBinaryCheck(config.targetPath))
appendLine() appendLine()
// 设置日志启用状态 if (shouldConfigureInService(config)) {
generateLogSettingSection(enableLog) // 添加SUS路径 (仅在不支持隐藏挂载时)
if (!config.support158 && config.susPaths.isNotEmpty()) {
generateSusPathsSection(config.susPaths)
}
// 添加SUS路径 // 添加Kstat配置
generateSusPathsSection(susPaths) generateKstatSection(config.kstatConfigs, config.addKstatPaths)
// 添加Kstat配置 // 设置uname和构建时间
generateKstatSection(kstatConfigs, addKstatPaths) generateUnameSection(config)
// 设置uname和构建时间 }
generateUnameSection(unameValue, buildTimeValue, executeInPostFsData)
// 添加日志设置
generateLogSettingSection(config.enableLog)
// 隐藏BL相关配置 // 隐藏BL相关配置
generateHideBlSection() generateHideBlSection()
@@ -85,6 +87,16 @@ object ScriptGenerator {
} }
} }
/**
* 判断是否需要在service中配置
*/
private fun shouldConfigureInService(config: SuSFSManager.ModuleConfig): Boolean {
return config.susPaths.isNotEmpty() ||
config.kstatConfigs.isNotEmpty() ||
config.addKstatPaths.isNotEmpty() ||
(!config.executeInPostFsData && (config.unameValue != DEFAULT_UNAME || config.buildTimeValue != DEFAULT_BUILD_TIME))
}
private fun StringBuilder.generateLogSettingSection(enableLog: Boolean) { private fun StringBuilder.generateLogSettingSection(enableLog: Boolean) {
appendLine("# 设置日志启用状态") appendLine("# 设置日志启用状态")
val logValue = if (enableLog) 1 else 0 val logValue = if (enableLog) 1 else 0
@@ -137,15 +149,11 @@ object ScriptGenerator {
} }
} }
private fun StringBuilder.generateUnameSection( private fun StringBuilder.generateUnameSection(config: SuSFSManager.ModuleConfig) {
unameValue: String, if (!config.executeInPostFsData && (config.unameValue != DEFAULT_UNAME || config.buildTimeValue != DEFAULT_BUILD_TIME)) {
buildTimeValue: String,
executeInPostFsData: Boolean
) {
if (!executeInPostFsData && (unameValue != DEFAULT_UNAME || buildTimeValue != DEFAULT_BUILD_TIME)) {
appendLine("# 设置uname和构建时间") appendLine("# 设置uname和构建时间")
appendLine("\"${'$'}SUSFS_BIN\" set_uname '$unameValue' '$buildTimeValue'") appendLine("\"${'$'}SUSFS_BIN\" set_uname '${config.unameValue}' '${config.buildTimeValue}'")
appendLine("echo \"$(get_current_time): 设置uname为: $unameValue, 构建时间为: $buildTimeValue\" >> \"${'$'}LOG_FILE\"") appendLine("echo \"$(get_current_time): 设置uname为: ${config.unameValue}, 构建时间为: ${config.buildTimeValue}\" >> \"${'$'}LOG_FILE\"")
appendLine() appendLine()
} }
} }
@@ -246,44 +254,24 @@ object ScriptGenerator {
/** /**
* 生成post-fs-data.sh脚本内容 * 生成post-fs-data.sh脚本内容
*/ */
fun generatePostFsDataScript( private fun generatePostFsDataScript(config: SuSFSManager.ModuleConfig): String {
targetPath: String,
unameValue: String,
buildTimeValue: String,
executeInPostFsData: Boolean = false,
androidDataPath: String = DEFAULT_ANDROID_DATA_PATH,
sdcardPath: String = DEFAULT_SDCARD_PATH
): String {
return buildString { return buildString {
appendLine("#!/system/bin/sh") appendLine("#!/system/bin/sh")
appendLine("# SuSFS Post-FS-Data Script") appendLine("# SuSFS Post-FS-Data Script")
appendLine("# 在文件系统挂载后但在系统完全启动前执行") appendLine("# 在文件系统挂载后但在系统完全启动前执行")
appendLine("# 优先级最高的配置项")
appendLine() appendLine()
appendLine(generateLogSetup("susfs_post_fs_data.log")) appendLine(generateLogSetup("susfs_post_fs_data.log"))
appendLine() appendLine()
appendLine(generateBinaryCheck(targetPath)) appendLine(generateBinaryCheck(config.targetPath))
appendLine() appendLine()
appendLine("echo \"$(get_current_time): Post-FS-Data脚本开始执行\" >> \"${'$'}LOG_FILE\"") appendLine("echo \"$(get_current_time): Post-FS-Data脚本开始执行\" >> \"${'$'}LOG_FILE\"")
appendLine() appendLine()
// 路径设置
appendLine("# 设置路径配置(优先级最高)")
appendLine("# 设置Android Data路径")
appendLine("\"${'$'}SUSFS_BIN\" set_android_data_root_path '$androidDataPath'")
appendLine("echo \"$(get_current_time): Android Data路径设置为: $androidDataPath\" >> \"${'$'}LOG_FILE\"")
appendLine()
appendLine("# 设置SD卡路径")
appendLine("\"${'$'}SUSFS_BIN\" set_sdcard_root_path '$sdcardPath'")
appendLine("echo \"$(get_current_time): SD卡路径设置为: $sdcardPath\" >> \"${'$'}LOG_FILE\"")
appendLine()
// 设置uname和构建时间 - 只有在选择在post-fs-data中执行时才执行 // 设置uname和构建时间 - 只有在选择在post-fs-data中执行时才执行
if (executeInPostFsData && (unameValue != DEFAULT_UNAME || buildTimeValue != DEFAULT_BUILD_TIME)) { if (config.executeInPostFsData && (config.unameValue != DEFAULT_UNAME || config.buildTimeValue != DEFAULT_BUILD_TIME)) {
appendLine("# 设置uname和构建时间") appendLine("# 设置uname和构建时间")
appendLine("\"${'$'}SUSFS_BIN\" set_uname '$unameValue' '$buildTimeValue'") appendLine("\"${'$'}SUSFS_BIN\" set_uname '${config.unameValue}' '${config.buildTimeValue}'")
appendLine("echo \"$(get_current_time): 设置uname为: $unameValue, 构建时间为: $buildTimeValue\" >> \"${'$'}LOG_FILE\"") appendLine("echo \"$(get_current_time): 设置uname为: ${config.unameValue}, 构建时间为: ${config.buildTimeValue}\" >> \"${'$'}LOG_FILE\"")
appendLine() appendLine()
} }
@@ -294,11 +282,7 @@ object ScriptGenerator {
/** /**
* 生成post-mount.sh脚本内容 * 生成post-mount.sh脚本内容
*/ */
fun generatePostMountScript( private fun generatePostMountScript(config: SuSFSManager.ModuleConfig): String {
targetPath: String,
susMounts: Set<String>,
tryUmounts: Set<String>
): String {
return buildString { return buildString {
appendLine("#!/system/bin/sh") appendLine("#!/system/bin/sh")
appendLine("# SuSFS Post-Mount Script") appendLine("# SuSFS Post-Mount Script")
@@ -308,13 +292,13 @@ object ScriptGenerator {
appendLine() appendLine()
appendLine("echo \"$(get_current_time): Post-Mount脚本开始执行\" >> \"${'$'}LOG_FILE\"") appendLine("echo \"$(get_current_time): Post-Mount脚本开始执行\" >> \"${'$'}LOG_FILE\"")
appendLine() appendLine()
appendLine(generateBinaryCheck(targetPath)) appendLine(generateBinaryCheck(config.targetPath))
appendLine() appendLine()
// 添加SUS挂载 // 添加SUS挂载
if (susMounts.isNotEmpty()) { if (config.susMounts.isNotEmpty()) {
appendLine("# 添加SUS挂载") appendLine("# 添加SUS挂载")
susMounts.forEach { mount -> config.susMounts.forEach { mount ->
appendLine("\"${'$'}SUSFS_BIN\" add_sus_mount '$mount'") appendLine("\"${'$'}SUSFS_BIN\" add_sus_mount '$mount'")
appendLine("echo \"$(get_current_time): 添加SUS挂载: $mount\" >> \"${'$'}LOG_FILE\"") appendLine("echo \"$(get_current_time): 添加SUS挂载: $mount\" >> \"${'$'}LOG_FILE\"")
} }
@@ -322,9 +306,9 @@ object ScriptGenerator {
} }
// 添加尝试卸载 // 添加尝试卸载
if (tryUmounts.isNotEmpty()) { if (config.tryUmounts.isNotEmpty()) {
appendLine("# 添加尝试卸载") appendLine("# 添加尝试卸载")
tryUmounts.forEach { umount -> config.tryUmounts.forEach { umount ->
val parts = umount.split("|") val parts = umount.split("|")
if (parts.size == 2) { if (parts.size == 2) {
val path = parts[0] val path = parts[0]
@@ -343,10 +327,7 @@ object ScriptGenerator {
/** /**
* 生成boot-completed.sh脚本内容 * 生成boot-completed.sh脚本内容
*/ */
fun generateBootCompletedScript( private fun generateBootCompletedScript(config: SuSFSManager.ModuleConfig): String {
targetPath: String,
hideSusMountsForAllProcs: Boolean = true
): String {
return buildString { return buildString {
appendLine("#!/system/bin/sh") appendLine("#!/system/bin/sh")
appendLine("# SuSFS Boot-Completed Script") appendLine("# SuSFS Boot-Completed Script")
@@ -356,36 +337,49 @@ object ScriptGenerator {
appendLine() appendLine()
appendLine("echo \"$(get_current_time): Boot-Completed脚本开始执行\" >> \"${'$'}LOG_FILE\"") appendLine("echo \"$(get_current_time): Boot-Completed脚本开始执行\" >> \"${'$'}LOG_FILE\"")
appendLine() appendLine()
appendLine(generateBinaryCheck(targetPath)) appendLine(generateBinaryCheck(config.targetPath))
appendLine() appendLine()
// SUS挂载隐藏控制仅限1.5.8及以上版本 // 仅在支持隐藏挂载功能时执行相关配置
appendLine("# 设置SUS挂载隐藏控制仅限1.5.8及以上版本)") if (config.support158) {
appendLine("SUSFS_VERSION=$(${'$'}SUSFS_BIN show version 2>/dev/null | grep -o 'v[0-9]\\+\\.[0-9]\\+\\.[0-9]\\+' | head -1)") // SUS挂载隐藏控制
appendLine("if [ -n \"${'$'}SUSFS_VERSION\" ]; then") val hideValue = if (config.hideSusMountsForAllProcs) 1 else 0
appendLine(" VERSION_NUM=$(echo \"${'$'}SUSFS_VERSION\" | sed 's/v//' | awk -F. '{printf \"%d%02d%02d\", $1, $2, $3}')") appendLine("# 设置SUS挂载隐藏控制")
appendLine(" if [ \"${'$'}VERSION_NUM\" -ge 10508 ]; then") appendLine("\"${'$'}SUSFS_BIN\" hide_sus_mnts_for_all_procs $hideValue")
val hideValue = if (hideSusMountsForAllProcs) 1 else 0 appendLine("echo \"$(get_current_time): SUS挂载隐藏控制设置为: ${if (config.hideSusMountsForAllProcs) "对所有进程隐藏" else "仅对非KSU进程隐藏"}\" >> \"${'$'}LOG_FILE\"")
appendLine(" \"${'$'}SUSFS_BIN\" hide_sus_mnts_for_all_procs $hideValue") appendLine()
appendLine(" echo \"$(get_current_time): SUS挂载隐藏控制设置为: ${if (hideSusMountsForAllProcs) "对所有进程隐藏" else "仅对非KSU进程隐藏"}\" >> \"${'$'}LOG_FILE\"")
appendLine(" else") // 路径设置和SUS路径设置
appendLine(" echo \"$(get_current_time): 当前版本 ${'$'}SUSFS_VERSION 不支持SUS挂载隐藏控制功能需要1.5.8及以上版本\" >> \"${'$'}LOG_FILE\"") if (config.susPaths.isNotEmpty()) {
appendLine(" fi") generatePathSettingSection(config.androidDataPath, config.sdcardPath)
appendLine("else") generateSusPathsSection(config.susPaths)
appendLine(" echo \"$(get_current_time): 无法获取SuSFS版本信息跳过SUS挂载隐藏控制设置\" >> \"${'$'}LOG_FILE\"") }
appendLine("fi") }
appendLine()
appendLine("echo \"$(get_current_time): Boot-Completed脚本执行完成\" >> \"${'$'}LOG_FILE\"") appendLine("echo \"$(get_current_time): Boot-Completed脚本执行完成\" >> \"${'$'}LOG_FILE\"")
} }
} }
@SuppressLint("SdCardPath")
private fun StringBuilder.generatePathSettingSection(androidDataPath: String, sdcardPath: String) {
appendLine("# 路径配置")
appendLine("# 设置Android Data路径")
appendLine("until [ -d \"/sdcard/Android\" ]; do sleep 1; done")
appendLine("\"${'$'}SUSFS_BIN\" set_android_data_root_path '$androidDataPath'")
appendLine("echo \"$(get_current_time): Android Data路径设置为: $androidDataPath\" >> \"${'$'}LOG_FILE\"")
appendLine()
appendLine("# 设置SD卡路径")
appendLine("\"${'$'}SUSFS_BIN\" set_sdcard_root_path '$sdcardPath'")
appendLine("echo \"$(get_current_time): SD卡路径设置为: $sdcardPath\" >> \"${'$'}LOG_FILE\"")
appendLine()
}
/** /**
* 生成module.prop文件内容 * 生成module.prop文件内容
*/ */
fun generateModuleProp(moduleId: String): String { fun generateModuleProp(moduleId: String): String {
val moduleVersion = "v1.0.0" val moduleVersion = "v1.0.1"
val moduleVersionCode = "1000" val moduleVersionCode = "1001"
return """ return """
id=$moduleId id=$moduleId

View File

@@ -392,7 +392,6 @@
<string name="susfs_tab_path_settings">パスの設定</string> <string name="susfs_tab_path_settings">パスの設定</string>
<string name="susfs_tab_enabled_features">有効な機能のステータス</string> <string name="susfs_tab_enabled_features">有効な機能のステータス</string>
<!-- SuSFS Dialog Actions --> <!-- SuSFS Dialog Actions -->
<string name="susfs_add">追加</string>
<!-- SuSFS Path Management --> <!-- SuSFS Path Management -->
<string name="susfs_add_sus_path">SUS パスを追加</string> <string name="susfs_add_sus_path">SUS パスを追加</string>
<string name="susfs_add_sus_mount">SUS マウントを追加</string> <string name="susfs_add_sus_mount">SUS マウントを追加</string>

View File

@@ -393,7 +393,6 @@
<string name="susfs_tab_path_settings">Настройки пути</string> <string name="susfs_tab_path_settings">Настройки пути</string>
<string name="susfs_tab_enabled_features">Статус включённых функций</string> <string name="susfs_tab_enabled_features">Статус включённых функций</string>
<!-- SuSFS Dialog Actions --> <!-- SuSFS Dialog Actions -->
<string name="susfs_add">Добавить</string>
<!-- SuSFS Path Management --> <!-- SuSFS Path Management -->
<string name="susfs_add_sus_path">Добавить SUS путь</string> <string name="susfs_add_sus_path">Добавить SUS путь</string>
<string name="susfs_add_sus_mount">Добавить SUS монтирование</string> <string name="susfs_add_sus_mount">Добавить SUS монтирование</string>

View File

@@ -391,7 +391,6 @@
<string name="susfs_tab_path_settings">Yol Ayarları</string> <string name="susfs_tab_path_settings">Yol Ayarları</string>
<string name="susfs_tab_enabled_features">Etkinleştirilen Özellikler Durumu</string> <string name="susfs_tab_enabled_features">Etkinleştirilen Özellikler Durumu</string>
<!-- SuSFS Dialog Actions --> <!-- SuSFS Dialog Actions -->
<string name="susfs_add">Ekle</string>
<!-- SuSFS Path Management --> <!-- SuSFS Path Management -->
<string name="susfs_add_sus_path">SUS Yolu Ekle</string> <string name="susfs_add_sus_path">SUS Yolu Ekle</string>
<string name="susfs_add_sus_mount">SUS Bağlama Noktası Ekle</string> <string name="susfs_add_sus_mount">SUS Bağlama Noktası Ekle</string>

View File

@@ -391,7 +391,6 @@
<string name="susfs_tab_path_settings">Cài đặt Đường dẫn</string> <string name="susfs_tab_path_settings">Cài đặt Đường dẫn</string>
<string name="susfs_tab_enabled_features">Trạng thái tính năng</string> <string name="susfs_tab_enabled_features">Trạng thái tính năng</string>
<!-- SuSFS Dialog Actions --> <!-- SuSFS Dialog Actions -->
<string name="susfs_add">Thêm</string>
<!-- SuSFS Path Management --> <!-- SuSFS Path Management -->
<string name="susfs_add_sus_path">Thêm Đường dẫn SuS</string> <string name="susfs_add_sus_path">Thêm Đường dẫn SuS</string>
<string name="susfs_add_sus_mount">Thêm SuS Mount</string> <string name="susfs_add_sus_mount">Thêm SuS Mount</string>

View File

@@ -391,7 +391,6 @@
<string name="susfs_tab_path_settings">路径设置</string> <string name="susfs_tab_path_settings">路径设置</string>
<string name="susfs_tab_enabled_features">启用功能状态</string> <string name="susfs_tab_enabled_features">启用功能状态</string>
<!-- SuSFS Dialog Actions --> <!-- SuSFS Dialog Actions -->
<string name="susfs_add">添加</string>
<!-- SuSFS Path Management --> <!-- SuSFS Path Management -->
<string name="susfs_add_sus_path">添加SUS路径</string> <string name="susfs_add_sus_path">添加SUS路径</string>
<string name="susfs_add_sus_mount">添加SUS挂载</string> <string name="susfs_add_sus_mount">添加SUS挂载</string>
@@ -519,4 +518,7 @@
<string name="susfs_run">运行</string> <string name="susfs_run">运行</string>
<string name="kernel_simple_kernel">内核版本简洁模式</string> <string name="kernel_simple_kernel">内核版本简洁模式</string>
<string name="kernel_simple_kernel_summary">启用或禁用SukiSU内核版本显示的简洁模式</string> <string name="kernel_simple_kernel_summary">启用或禁用SukiSU内核版本显示的简洁模式</string>
<string name="susfs_android_data_path_set">Android Data路径已设置为: %s</string>
<string name="susfs_sdcard_path_set">SD卡路径已设置为: %s</string>
<string name="susfs_path_setup_warning">路径设置可能未完全成功但将继续添加SUS路径</string>
</resources> </resources>

View File

@@ -390,7 +390,6 @@
<string name="susfs_tab_path_settings">路徑設定</string> <string name="susfs_tab_path_settings">路徑設定</string>
<string name="susfs_tab_enabled_features">啟用功能狀態</string> <string name="susfs_tab_enabled_features">啟用功能狀態</string>
<!-- SuSFS Dialog Actions --> <!-- SuSFS Dialog Actions -->
<string name="susfs_add">添加</string>
<!-- SuSFS Path Management --> <!-- SuSFS Path Management -->
<string name="susfs_add_sus_path">添加SUS路徑</string> <string name="susfs_add_sus_path">添加SUS路徑</string>
<string name="susfs_add_sus_mount">添加SUS掛載</string> <string name="susfs_add_sus_mount">添加SUS掛載</string>

View File

@@ -391,7 +391,6 @@
<string name="susfs_tab_path_settings">路徑設定</string> <string name="susfs_tab_path_settings">路徑設定</string>
<string name="susfs_tab_enabled_features">啟用功能狀態</string> <string name="susfs_tab_enabled_features">啟用功能狀態</string>
<!-- SuSFS Dialog Actions --> <!-- SuSFS Dialog Actions -->
<string name="susfs_add">新增</string>
<!-- SuSFS Path Management --> <!-- SuSFS Path Management -->
<string name="susfs_add_sus_path">新增 SUS 路徑</string> <string name="susfs_add_sus_path">新增 SUS 路徑</string>
<string name="susfs_add_sus_mount">新增 SUS 掛載</string> <string name="susfs_add_sus_mount">新增 SUS 掛載</string>

View File

@@ -392,8 +392,6 @@
<string name="susfs_tab_try_umount">Try Umount</string> <string name="susfs_tab_try_umount">Try Umount</string>
<string name="susfs_tab_path_settings">Path Settings</string> <string name="susfs_tab_path_settings">Path Settings</string>
<string name="susfs_tab_enabled_features">Enabled Features Status</string> <string name="susfs_tab_enabled_features">Enabled Features Status</string>
<!-- SuSFS Dialog Actions -->
<string name="susfs_add">Add</string>
<!-- SuSFS Path Management --> <!-- SuSFS Path Management -->
<string name="susfs_add_sus_path">Add SUS Path</string> <string name="susfs_add_sus_path">Add SUS Path</string>
<string name="susfs_add_sus_mount">Add SUS Mount</string> <string name="susfs_add_sus_mount">Add SUS Mount</string>
@@ -521,4 +519,7 @@
<string name="susfs_run">Run</string> <string name="susfs_run">Run</string>
<string name="kernel_simple_kernel">Kernel Version Concise Mode</string> <string name="kernel_simple_kernel">Kernel Version Concise Mode</string>
<string name="kernel_simple_kernel_summary">Enable or disable the clean mode displayed by the SukiSU kernel version</string> <string name="kernel_simple_kernel_summary">Enable or disable the clean mode displayed by the SukiSU kernel version</string>
<string name="susfs_android_data_path_set">Android Data path has been set to: %s</string>
<string name="susfs_sdcard_path_set">SD card path has been set to: %s</string>
<string name="susfs_path_setup_warning">Path setup may not be fully successful, but SUS paths will continue to be added</string>
</resources> </resources>