manager: Add pseudo kernel and build time execution location settings

This commit is contained in:
ShirkNeko
2025-06-17 23:30:29 +08:00
parent 6b1f73aa3d
commit af97488d58
5 changed files with 126 additions and 12 deletions

View File

@@ -120,6 +120,7 @@ fun SuSFSConfigScreen(
var autoStartEnabled by remember { mutableStateOf(false) } var autoStartEnabled by remember { mutableStateOf(false) }
var lastAppliedValue by remember { mutableStateOf("") } var lastAppliedValue by remember { mutableStateOf("") }
var lastAppliedBuildTime by remember { mutableStateOf("") } var lastAppliedBuildTime by remember { mutableStateOf("") }
var executeInPostFsData by remember { mutableStateOf(false) } // 新增是否在post-fs-data中执行
// 路径管理相关状态 // 路径管理相关状态
var susPaths by remember { mutableStateOf(emptySet<String>()) } var susPaths by remember { mutableStateOf(emptySet<String>()) }
@@ -173,6 +174,7 @@ fun SuSFSConfigScreen(
autoStartEnabled = SuSFSManager.isAutoStartEnabled(context) autoStartEnabled = SuSFSManager.isAutoStartEnabled(context)
lastAppliedValue = SuSFSManager.getLastAppliedValue(context) lastAppliedValue = SuSFSManager.getLastAppliedValue(context)
lastAppliedBuildTime = SuSFSManager.getLastAppliedBuildTime(context) lastAppliedBuildTime = SuSFSManager.getLastAppliedBuildTime(context)
executeInPostFsData = SuSFSManager.getExecuteInPostFsData(context) // 加载执行位置设置
susPaths = SuSFSManager.getSusPaths(context) susPaths = SuSFSManager.getSusPaths(context)
susMounts = SuSFSManager.getSusMounts(context) susMounts = SuSFSManager.getSusMounts(context)
tryUmounts = SuSFSManager.getTryUmounts(context) tryUmounts = SuSFSManager.getTryUmounts(context)
@@ -706,6 +708,8 @@ fun SuSFSConfigScreen(
if (success) { if (success) {
lastAppliedValue = finalUnameValue lastAppliedValue = finalUnameValue
lastAppliedBuildTime = finalBuildTimeValue lastAppliedBuildTime = finalBuildTimeValue
// 保存执行位置设置
SuSFSManager.saveExecuteInPostFsData(context, executeInPostFsData)
} }
isLoading = false isLoading = false
} }
@@ -920,6 +924,8 @@ fun SuSFSConfigScreen(
onUnameValueChange = { unameValue = it }, onUnameValueChange = { unameValue = it },
buildTimeValue = buildTimeValue, buildTimeValue = buildTimeValue,
onBuildTimeValueChange = { buildTimeValue = it }, onBuildTimeValueChange = { buildTimeValue = it },
executeInPostFsData = executeInPostFsData,
onExecuteInPostFsDataChange = { executeInPostFsData = it },
autoStartEnabled = autoStartEnabled, autoStartEnabled = autoStartEnabled,
canEnableAutoStart = canEnableAutoStart, canEnableAutoStart = canEnableAutoStart,
isLoading = isLoading, isLoading = isLoading,
@@ -1024,18 +1030,23 @@ fun SuSFSConfigScreen(
/** /**
* 基本设置内容组件 * 基本设置内容组件
*/ */
@OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
private fun BasicSettingsContent( private fun BasicSettingsContent(
unameValue: String, unameValue: String,
onUnameValueChange: (String) -> Unit, onUnameValueChange: (String) -> Unit,
buildTimeValue: String, buildTimeValue: String,
onBuildTimeValueChange: (String) -> Unit, onBuildTimeValueChange: (String) -> Unit,
executeInPostFsData: Boolean,
onExecuteInPostFsDataChange: (Boolean) -> Unit,
autoStartEnabled: Boolean, autoStartEnabled: Boolean,
canEnableAutoStart: Boolean, canEnableAutoStart: Boolean,
isLoading: Boolean, isLoading: Boolean,
onAutoStartToggle: (Boolean) -> Unit, onAutoStartToggle: (Boolean) -> Unit,
context: android.content.Context context: android.content.Context
) { ) {
var scriptLocationExpanded by remember { mutableStateOf(false) }
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
@@ -1093,6 +1104,65 @@ private fun BasicSettingsContent(
shape = RoundedCornerShape(8.dp) shape = RoundedCornerShape(8.dp)
) )
// 执行位置选择
ExposedDropdownMenuBox(
expanded = scriptLocationExpanded,
onExpandedChange = { scriptLocationExpanded = !scriptLocationExpanded }
) {
OutlinedTextField(
value = if (executeInPostFsData)
stringResource(R.string.susfs_execution_location_post_fs_data)
else
stringResource(R.string.susfs_execution_location_service),
onValueChange = { },
readOnly = true,
label = { Text(stringResource(R.string.susfs_execution_location_label)) },
trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = scriptLocationExpanded) },
modifier = Modifier
.fillMaxWidth()
.menuAnchor(MenuAnchorType.PrimaryEditable, true),
shape = RoundedCornerShape(8.dp),
enabled = !isLoading
)
ExposedDropdownMenu(
expanded = scriptLocationExpanded,
onDismissRequest = { scriptLocationExpanded = false }
) {
DropdownMenuItem(
text = {
Column {
Text(stringResource(R.string.susfs_execution_location_service))
Text(
stringResource(R.string.susfs_execution_location_service_description),
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
},
onClick = {
onExecuteInPostFsDataChange(false)
scriptLocationExpanded = false
}
)
DropdownMenuItem(
text = {
Column {
Text(stringResource(R.string.susfs_execution_location_post_fs_data))
Text(
stringResource(R.string.susfs_execution_location_post_fs_data_description),
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
},
onClick = {
onExecuteInPostFsDataChange(true)
scriptLocationExpanded = false
}
)
}
}
// 当前值显示 // 当前值显示
Column( Column(
verticalArrangement = Arrangement.spacedBy(4.dp) verticalArrangement = Arrangement.spacedBy(4.dp)
@@ -1107,6 +1177,11 @@ private fun BasicSettingsContent(
style = MaterialTheme.typography.bodyMedium, style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant color = MaterialTheme.colorScheme.onSurfaceVariant
) )
Text(
text = "当前执行位置: ${if (SuSFSManager.getExecuteInPostFsData(context)) "Post-FS-Data" else "Service"}",
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
} }
// 开机自启动开关 // 开机自启动开关

View File

@@ -33,6 +33,7 @@ object SuSFSManager {
private const val KEY_ANDROID_DATA_PATH = "android_data_path" private const val KEY_ANDROID_DATA_PATH = "android_data_path"
private const val KEY_SDCARD_PATH = "sdcard_path" private const val KEY_SDCARD_PATH = "sdcard_path"
private const val KEY_ENABLE_LOG = "enable_log" private const val KEY_ENABLE_LOG = "enable_log"
private const val KEY_EXECUTE_IN_POST_FS_DATA = "execute_in_post_fs_data"
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"
@@ -119,6 +120,23 @@ object SuSFSManager {
return getPrefs(context).getString(KEY_BUILD_TIME_VALUE, DEFAULT_BUILD_TIME) ?: DEFAULT_BUILD_TIME return getPrefs(context).getString(KEY_BUILD_TIME_VALUE, DEFAULT_BUILD_TIME) ?: DEFAULT_BUILD_TIME
} }
/**
* 保存执行位置设置
*/
fun saveExecuteInPostFsData(context: Context, executeInPostFsData: Boolean) {
getPrefs(context).edit().apply {
putBoolean(KEY_EXECUTE_IN_POST_FS_DATA, executeInPostFsData)
apply()
}
}
/**
* 获取执行位置设置
*/
fun getExecuteInPostFsData(context: Context): Boolean {
return getPrefs(context).getBoolean(KEY_EXECUTE_IN_POST_FS_DATA, false)
}
/** /**
* 保存最后应用的值 * 保存最后应用的值
*/ */
@@ -360,6 +378,7 @@ object SuSFSManager {
// 获取配置信息 // 获取配置信息
val unameValue = getUnameValue(context) val unameValue = getUnameValue(context)
val buildTimeValue = getBuildTimeValue(context) val buildTimeValue = getBuildTimeValue(context)
val executeInPostFsData = getExecuteInPostFsData(context)
val susPaths = getSusPaths(context) val susPaths = getSusPaths(context)
val susMounts = getSusMounts(context) val susMounts = getSusMounts(context)
val tryUmounts = getTryUmounts(context) val tryUmounts = getTryUmounts(context)
@@ -370,7 +389,7 @@ object SuSFSManager {
// 生成并创建service.sh // 生成并创建service.sh
val serviceScript = ScriptGenerator.generateServiceScript( val serviceScript = ScriptGenerator.generateServiceScript(
targetPath, unameValue, buildTimeValue, susPaths, targetPath, unameValue, buildTimeValue, susPaths,
androidDataPath, sdcardPath, enableLog androidDataPath, sdcardPath, enableLog, executeInPostFsData
) )
val createServiceResult = shell.newJob() val createServiceResult = shell.newJob()
.add("cat > $MODULE_PATH/service.sh << 'EOF'\n$serviceScript\nEOF") .add("cat > $MODULE_PATH/service.sh << 'EOF'\n$serviceScript\nEOF")
@@ -381,7 +400,9 @@ object SuSFSManager {
} }
// 生成并创建post-fs-data.sh // 生成并创建post-fs-data.sh
val postFsDataScript = ScriptGenerator.generatePostFsDataScript(targetPath) val postFsDataScript = ScriptGenerator.generatePostFsDataScript(
targetPath, unameValue, buildTimeValue, executeInPostFsData
)
val createPostFsDataResult = shell.newJob() val createPostFsDataResult = shell.newJob()
.add("cat > $MODULE_PATH/post-fs-data.sh << 'EOF'\n$postFsDataScript\nEOF") .add("cat > $MODULE_PATH/post-fs-data.sh << 'EOF'\n$postFsDataScript\nEOF")
.add("chmod 755 $MODULE_PATH/post-fs-data.sh") .add("chmod 755 $MODULE_PATH/post-fs-data.sh")
@@ -731,6 +752,7 @@ object SuSFSManager {
/** /**
* 执行SuSFS命令设置uname和构建时间 * 执行SuSFS命令设置uname和构建时间
*/ */
@SuppressLint("StringFormatMatches")
suspend fun setUname(context: Context, unameValue: String, buildTimeValue: String): Boolean = withContext(Dispatchers.IO) { suspend fun setUname(context: Context, unameValue: String, buildTimeValue: String): Boolean = withContext(Dispatchers.IO) {
try { try {
// 首先复制二进制文件到/data/adb/ksu/bin/ // 首先复制二进制文件到/data/adb/ksu/bin/

View File

@@ -19,7 +19,8 @@ object ScriptGenerator {
susPaths: Set<String>, susPaths: Set<String>,
androidDataPath: String, androidDataPath: String,
sdcardPath: String, sdcardPath: String,
enableLog: Boolean enableLog: Boolean,
executeInPostFsData: Boolean = false
): String { ): String {
return buildString { return buildString {
appendLine("#!/system/bin/sh") appendLine("#!/system/bin/sh")
@@ -79,8 +80,8 @@ object ScriptGenerator {
appendLine() appendLine()
} }
// 设置uname和构建时间 // 设置uname和构建时间 - 只有不在service中执行
if (unameValue != "default" || buildTimeValue != "default") { if (!executeInPostFsData && (unameValue != "default" || buildTimeValue != "default")) {
appendLine("# 设置uname和构建时间") appendLine("# 设置uname和构建时间")
appendLine("\"\$SUSFS_BIN\" set_uname '$unameValue' '$buildTimeValue'") appendLine("\"\$SUSFS_BIN\" set_uname '$unameValue' '$buildTimeValue'")
appendLine("echo \"\$(get_current_time): 设置uname为: $unameValue, 构建时间为: $buildTimeValue\" >> \"\$LOG_FILE\"") appendLine("echo \"\$(get_current_time): 设置uname为: $unameValue, 构建时间为: $buildTimeValue\" >> \"\$LOG_FILE\"")
@@ -177,6 +178,9 @@ object ScriptGenerator {
*/ */
fun generatePostFsDataScript( fun generatePostFsDataScript(
targetPath: String, targetPath: String,
unameValue: String,
buildTimeValue: String,
executeInPostFsData: Boolean = false
): String { ): String {
return buildString { return buildString {
appendLine("#!/system/bin/sh") appendLine("#!/system/bin/sh")
@@ -204,9 +208,15 @@ object ScriptGenerator {
appendLine() appendLine()
appendLine("echo \"\$(get_current_time): Post-FS-Data脚本开始执行\" >> \"\$LOG_FILE\"") appendLine("echo \"\$(get_current_time): Post-FS-Data脚本开始执行\" >> \"\$LOG_FILE\"")
appendLine() appendLine()
// 设置uname和构建时间 - 只有在选择在post-fs-data中执行时才执行
if (executeInPostFsData && (unameValue != "default" || buildTimeValue != "default")) {
appendLine("# 设置uname和构建时间")
appendLine("\"\$SUSFS_BIN\" set_uname '$unameValue' '$buildTimeValue'")
appendLine("echo \"\$(get_current_time): 设置uname为: $unameValue, 构建时间为: $buildTimeValue\" >> \"\$LOG_FILE\"")
appendLine() appendLine()
appendLine() }
appendLine()
appendLine("echo \"\$(get_current_time): Post-FS-Data脚本执行完成\" >> \"\$LOG_FILE\"") appendLine("echo \"\$(get_current_time): Post-FS-Data脚本执行完成\" >> \"\$LOG_FILE\"")
} }
} }
@@ -305,9 +315,6 @@ object ScriptGenerator {
appendLine(" exit 1") appendLine(" exit 1")
appendLine("fi") appendLine("fi")
appendLine() appendLine()
appendLine()
appendLine()
appendLine()
appendLine("echo \"\$(get_current_time): Boot-Completed脚本执行完成\" >> \"\$LOG_FILE\"") appendLine("echo \"\$(get_current_time): Boot-Completed脚本执行完成\" >> \"\$LOG_FILE\"")
} }
} }
@@ -325,7 +332,7 @@ object ScriptGenerator {
version=$moduleVersion version=$moduleVersion
versionCode=$moduleVersionCode versionCode=$moduleVersionCode
author=ShirkNeko author=ShirkNeko
description=SuSFS Manager Auto Configuration Module description=SuSFS Manager Auto Configuration Module (自动生成请不要手动卸载或删除该模块! / Automatically generated Please do not manually uninstall or delete the module!)
updateJson= updateJson=
""".trimIndent() """.trimIndent()
} }

View File

@@ -522,4 +522,9 @@
<string name="show_module_update_json_summary">在模块详情中显示更新配置URL</string> <string name="show_module_update_json_summary">在模块详情中显示更新配置URL</string>
<string name="show_more_module_info">显示更多模块信息</string> <string name="show_more_module_info">显示更多模块信息</string>
<string name="show_more_module_info_summary">显示额外的模块信息如更新配置URL等</string> <string name="show_more_module_info_summary">显示额外的模块信息如更新配置URL等</string>
<string name="susfs_execution_location_label">执行位置</string>
<string name="susfs_execution_location_service">Service</string>
<string name="susfs_execution_location_post_fs_data">Post-FS-Data</string>
<string name="susfs_execution_location_service_description">在系统服务启动后执行</string>
<string name="susfs_execution_location_post_fs_data_description">在文件系统挂载后但系统完全启动前执行,可能会导致循环重启</string>
</resources> </resources>

View File

@@ -524,4 +524,9 @@
<string name="show_module_update_json_summary">Display update JSON URL in module details</string> <string name="show_module_update_json_summary">Display update JSON URL in module details</string>
<string name="show_more_module_info">Show More Module Info</string> <string name="show_more_module_info">Show More Module Info</string>
<string name="show_more_module_info_summary">Display additional module information like update JSON URLs</string> <string name="show_more_module_info_summary">Display additional module information like update JSON URLs</string>
<string name="susfs_execution_location_label">Execution Location</string>
<string name="susfs_execution_location_service">Service</string>
<string name="susfs_execution_location_post_fs_data">Post-FS-Data</string>
<string name="susfs_execution_location_service_description">Execute after system services start</string>
<string name="susfs_execution_location_post_fs_data_description">Execute after file system is mounted but before system is fully bootedMay cause a boot loop</string>
</resources> </resources>