manager: Refactoring get the status of SUSFS functions
- More precise status cases - Requires a recompile of your kernel to use it.
This commit is contained in:
@@ -300,3 +300,51 @@ NativeBridgeNP(getHookType, jstring) {
|
|||||||
get_hook_type(hook_type, sizeof(hook_type));
|
get_hook_type(hook_type, sizeof(hook_type));
|
||||||
return GetEnvironment()->NewStringUTF(env, hook_type);
|
return GetEnvironment()->NewStringUTF(env, hook_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NativeBridgeNP(getSusfsFeatureStatus, jobject) {
|
||||||
|
struct susfs_feature_status status;
|
||||||
|
bool result = get_susfs_feature_status(&status);
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
jclass cls = GetEnvironment()->FindClass(env, "com/sukisu/ultra/Natives$SusfsFeatureStatus");
|
||||||
|
jmethodID constructor = GetEnvironment()->GetMethodID(env, cls, "<init>", "()V");
|
||||||
|
jobject obj = GetEnvironment()->NewObject(env, cls, constructor);
|
||||||
|
|
||||||
|
// 设置各个字段
|
||||||
|
jfieldID statusSusPathField = GetEnvironment()->GetFieldID(env, cls, "statusSusPath", "Z");
|
||||||
|
jfieldID statusSusMountField = GetEnvironment()->GetFieldID(env, cls, "statusSusMount", "Z");
|
||||||
|
jfieldID statusAutoDefaultMountField = GetEnvironment()->GetFieldID(env, cls, "statusAutoDefaultMount", "Z");
|
||||||
|
jfieldID statusAutoBindMountField = GetEnvironment()->GetFieldID(env, cls, "statusAutoBindMount", "Z");
|
||||||
|
jfieldID statusSusKstatField = GetEnvironment()->GetFieldID(env, cls, "statusSusKstat", "Z");
|
||||||
|
jfieldID statusTryUmountField = GetEnvironment()->GetFieldID(env, cls, "statusTryUmount", "Z");
|
||||||
|
jfieldID statusAutoTryUmountBindField = GetEnvironment()->GetFieldID(env, cls, "statusAutoTryUmountBind", "Z");
|
||||||
|
jfieldID statusSpoofUnameField = GetEnvironment()->GetFieldID(env, cls, "statusSpoofUname", "Z");
|
||||||
|
jfieldID statusEnableLogField = GetEnvironment()->GetFieldID(env, cls, "statusEnableLog", "Z");
|
||||||
|
jfieldID statusHideSymbolsField = GetEnvironment()->GetFieldID(env, cls, "statusHideSymbols", "Z");
|
||||||
|
jfieldID statusSpoofCmdlineField = GetEnvironment()->GetFieldID(env, cls, "statusSpoofCmdline", "Z");
|
||||||
|
jfieldID statusOpenRedirectField = GetEnvironment()->GetFieldID(env, cls, "statusOpenRedirect", "Z");
|
||||||
|
jfieldID statusMagicMountField = GetEnvironment()->GetFieldID(env, cls, "statusMagicMount", "Z");
|
||||||
|
jfieldID statusOverlayfsAutoKstatField = GetEnvironment()->GetFieldID(env, cls, "statusOverlayfsAutoKstat", "Z");
|
||||||
|
jfieldID statusSusSuField = GetEnvironment()->GetFieldID(env, cls, "statusSusSu", "Z");
|
||||||
|
|
||||||
|
GetEnvironment()->SetBooleanField(env, obj, statusSusPathField, status.status_sus_path);
|
||||||
|
GetEnvironment()->SetBooleanField(env, obj, statusSusMountField, status.status_sus_mount);
|
||||||
|
GetEnvironment()->SetBooleanField(env, obj, statusAutoDefaultMountField, status.status_auto_default_mount);
|
||||||
|
GetEnvironment()->SetBooleanField(env, obj, statusAutoBindMountField, status.status_auto_bind_mount);
|
||||||
|
GetEnvironment()->SetBooleanField(env, obj, statusSusKstatField, status.status_sus_kstat);
|
||||||
|
GetEnvironment()->SetBooleanField(env, obj, statusTryUmountField, status.status_try_umount);
|
||||||
|
GetEnvironment()->SetBooleanField(env, obj, statusAutoTryUmountBindField, status.status_auto_try_umount_bind);
|
||||||
|
GetEnvironment()->SetBooleanField(env, obj, statusSpoofUnameField, status.status_spoof_uname);
|
||||||
|
GetEnvironment()->SetBooleanField(env, obj, statusEnableLogField, status.status_enable_log);
|
||||||
|
GetEnvironment()->SetBooleanField(env, obj, statusHideSymbolsField, status.status_hide_symbols);
|
||||||
|
GetEnvironment()->SetBooleanField(env, obj, statusSpoofCmdlineField, status.status_spoof_cmdline);
|
||||||
|
GetEnvironment()->SetBooleanField(env, obj, statusOpenRedirectField, status.status_open_redirect);
|
||||||
|
GetEnvironment()->SetBooleanField(env, obj, statusMagicMountField, status.status_magic_mount);
|
||||||
|
GetEnvironment()->SetBooleanField(env, obj, statusOverlayfsAutoKstatField, status.status_overlayfs_auto_kstat);
|
||||||
|
GetEnvironment()->SetBooleanField(env, obj, statusSusSuField, status.status_sus_su);
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
@@ -32,6 +32,7 @@
|
|||||||
#define CMD_ENABLE_SU 15
|
#define CMD_ENABLE_SU 15
|
||||||
#define CMD_ENABLE_KPM 100
|
#define CMD_ENABLE_KPM 100
|
||||||
#define CMD_HOOK_TYPE 101
|
#define CMD_HOOK_TYPE 101
|
||||||
|
#define CMD_GET_SUSFS_FEATURE_STATUS 102
|
||||||
|
|
||||||
static bool ksuctl(int cmd, void* arg1, void* arg2) {
|
static bool ksuctl(int cmd, void* arg1, void* arg2) {
|
||||||
int32_t result = 0;
|
int32_t result = 0;
|
||||||
@@ -124,3 +125,11 @@ bool get_hook_type(char* hook_type, size_t size) {
|
|||||||
hook_type[size - 1] = '\0';
|
hook_type[size - 1] = '\0';
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool get_susfs_feature_status(struct susfs_feature_status* status) {
|
||||||
|
if (status == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ksuctl(CMD_GET_SUSFS_FEATURE_STATUS, status, NULL);
|
||||||
|
}
|
||||||
@@ -26,6 +26,25 @@ bool is_lkm_mode();
|
|||||||
#define KSU_MAX_GROUPS 32
|
#define KSU_MAX_GROUPS 32
|
||||||
#define KSU_SELINUX_DOMAIN 64
|
#define KSU_SELINUX_DOMAIN 64
|
||||||
|
|
||||||
|
// SUSFS Functional State Structures
|
||||||
|
struct susfs_feature_status {
|
||||||
|
bool status_sus_path;
|
||||||
|
bool status_sus_mount;
|
||||||
|
bool status_auto_default_mount;
|
||||||
|
bool status_auto_bind_mount;
|
||||||
|
bool status_sus_kstat;
|
||||||
|
bool status_try_umount;
|
||||||
|
bool status_auto_try_umount_bind;
|
||||||
|
bool status_spoof_uname;
|
||||||
|
bool status_enable_log;
|
||||||
|
bool status_hide_symbols;
|
||||||
|
bool status_spoof_cmdline;
|
||||||
|
bool status_open_redirect;
|
||||||
|
bool status_magic_mount;
|
||||||
|
bool status_overlayfs_auto_kstat;
|
||||||
|
bool status_sus_su;
|
||||||
|
};
|
||||||
|
|
||||||
struct root_profile {
|
struct root_profile {
|
||||||
int32_t uid;
|
int32_t uid;
|
||||||
int32_t gid;
|
int32_t gid;
|
||||||
@@ -86,4 +105,6 @@ bool is_KPM_enable();
|
|||||||
|
|
||||||
bool get_hook_type(char* hook_type, size_t size);
|
bool get_hook_type(char* hook_type, size_t size);
|
||||||
|
|
||||||
|
bool get_susfs_feature_status(struct susfs_feature_status* status);
|
||||||
|
|
||||||
#endif //KERNELSU_KSU_H
|
#endif //KERNELSU_KSU_H
|
||||||
@@ -71,6 +71,12 @@ object Natives {
|
|||||||
external fun isKPMEnabled(): Boolean
|
external fun isKPMEnabled(): Boolean
|
||||||
external fun getHookType(): String
|
external fun getHookType(): String
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get SUSFS feature status from kernel
|
||||||
|
* @return SusfsFeatureStatus object containing all feature states, or null if failed
|
||||||
|
*/
|
||||||
|
external fun getSusfsFeatureStatus(): SusfsFeatureStatus?
|
||||||
|
|
||||||
private const val NON_ROOT_DEFAULT_PROFILE_KEY = "$"
|
private const val NON_ROOT_DEFAULT_PROFILE_KEY = "$"
|
||||||
private const val NOBODY_UID = 9999
|
private const val NOBODY_UID = 9999
|
||||||
|
|
||||||
@@ -95,6 +101,48 @@ object Natives {
|
|||||||
return version < MINIMAL_SUPPORTED_KERNEL
|
return version < MINIMAL_SUPPORTED_KERNEL
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Immutable
|
||||||
|
@Parcelize
|
||||||
|
@Keep
|
||||||
|
data class SusfsFeatureStatus(
|
||||||
|
val statusSusPath: Boolean = false,
|
||||||
|
val statusSusMount: Boolean = false,
|
||||||
|
val statusAutoDefaultMount: Boolean = false,
|
||||||
|
val statusAutoBindMount: Boolean = false,
|
||||||
|
val statusSusKstat: Boolean = false,
|
||||||
|
val statusTryUmount: Boolean = false,
|
||||||
|
val statusAutoTryUmountBind: Boolean = false,
|
||||||
|
val statusSpoofUname: Boolean = false,
|
||||||
|
val statusEnableLog: Boolean = false,
|
||||||
|
val statusHideSymbols: Boolean = false,
|
||||||
|
val statusSpoofCmdline: Boolean = false,
|
||||||
|
val statusOpenRedirect: Boolean = false,
|
||||||
|
val statusMagicMount: Boolean = false,
|
||||||
|
val statusOverlayfsAutoKstat: Boolean = false,
|
||||||
|
val statusSusSu: Boolean = false
|
||||||
|
) : Parcelable {
|
||||||
|
fun toMap(): Map<String, Boolean> {
|
||||||
|
return mapOf(
|
||||||
|
"CONFIG_KSU_SUSFS_SUS_PATH" to statusSusPath,
|
||||||
|
"CONFIG_KSU_SUSFS_SUS_MOUNT" to statusSusMount,
|
||||||
|
"CONFIG_KSU_SUSFS_AUTO_ADD_SUS_KSU_DEFAULT_MOUNT" to statusAutoDefaultMount,
|
||||||
|
"CONFIG_KSU_SUSFS_AUTO_ADD_SUS_BIND_MOUNT" to statusAutoBindMount,
|
||||||
|
"CONFIG_KSU_SUSFS_SUS_KSTAT" to statusSusKstat,
|
||||||
|
"CONFIG_KSU_SUSFS_TRY_UMOUNT" to statusTryUmount,
|
||||||
|
"CONFIG_KSU_SUSFS_AUTO_ADD_TRY_UMOUNT_FOR_BIND_MOUNT" to statusAutoTryUmountBind,
|
||||||
|
"CONFIG_KSU_SUSFS_SPOOF_UNAME" to statusSpoofUname,
|
||||||
|
"CONFIG_KSU_SUSFS_ENABLE_LOG" to statusEnableLog,
|
||||||
|
"CONFIG_KSU_SUSFS_HIDE_KSU_SUSFS_SYMBOLS" to statusHideSymbols,
|
||||||
|
"CONFIG_KSU_SUSFS_SPOOF_CMDLINE_OR_BOOTCONFIG" to statusSpoofCmdline,
|
||||||
|
"CONFIG_KSU_SUSFS_OPEN_REDIRECT" to statusOpenRedirect,
|
||||||
|
"CONFIG_KSU_SUSFS_HAS_MAGIC_MOUNT" to statusMagicMount,
|
||||||
|
"CONFIG_KSU_SUSFS_SUS_OVERLAYFS" to statusOverlayfsAutoKstat,
|
||||||
|
"CONFIG_KSU_SUSFS_SUS_SU" to statusSusSu
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
@Parcelize
|
@Parcelize
|
||||||
@Keep
|
@Keep
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import android.content.Context
|
|||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import com.dergoogler.mmrl.platform.Platform.Companion.context
|
import com.dergoogler.mmrl.platform.Platform.Companion.context
|
||||||
|
import com.sukisu.ultra.Natives
|
||||||
import com.sukisu.ultra.R
|
import com.sukisu.ultra.R
|
||||||
import com.topjohnwu.superuser.Shell
|
import com.topjohnwu.superuser.Shell
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
@@ -13,7 +14,6 @@ import kotlinx.coroutines.withContext
|
|||||||
import java.io.FileOutputStream
|
import java.io.FileOutputStream
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.zip.GZIPInputStream
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SuSFS 配置管理器
|
* SuSFS 配置管理器
|
||||||
@@ -71,25 +71,6 @@ object SuSFSManager {
|
|||||||
val canConfigure: Boolean = false // 是否可配置(通过弹窗)
|
val canConfigure: Boolean = false // 是否可配置(通过弹窗)
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
|
||||||
* 功能配置映射数据类
|
|
||||||
*/
|
|
||||||
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实例
|
* 获取Root Shell实例
|
||||||
*/
|
*/
|
||||||
@@ -303,56 +284,6 @@ object SuSFSManager {
|
|||||||
return getPrefs(context).getString(KEY_SDCARD_PATH, "/sdcard") ?: "/sdcard"
|
return getPrefs(context).getString(KEY_SDCARD_PATH, "/sdcard") ?: "/sdcard"
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 读取并解析/proc/config.gz文件
|
|
||||||
*/
|
|
||||||
private suspend fun readProcConfig(): Map<String, String> = withContext(Dispatchers.IO) {
|
|
||||||
val configMap = mutableMapOf<String, String>()
|
|
||||||
try {
|
|
||||||
val shell = getRootShell()
|
|
||||||
|
|
||||||
// 首先检查/proc/config.gz是否存在
|
|
||||||
val checkResult = shell.newJob().add("test -f /proc/config.gz").exec()
|
|
||||||
if (!checkResult.isSuccess) {
|
|
||||||
return@withContext configMap
|
|
||||||
}
|
|
||||||
|
|
||||||
// 读取并解压/proc/config.gz
|
|
||||||
val result = shell.newJob().add("zcat /proc/config.gz").exec()
|
|
||||||
if (result.isSuccess) {
|
|
||||||
result.out.forEach { line ->
|
|
||||||
val trimmedLine = line.trim()
|
|
||||||
when {
|
|
||||||
// 处理启用的配置项 CONFIG_XXX=y
|
|
||||||
trimmedLine.contains("=y") -> {
|
|
||||||
val configName = trimmedLine.substringBefore("=y")
|
|
||||||
if (configName.startsWith("CONFIG_")) {
|
|
||||||
configMap[configName] = "y"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 处理未启用的配置项 # CONFIG_XXX is not set
|
|
||||||
trimmedLine.startsWith("# ") && trimmedLine.endsWith(" is not set") -> {
|
|
||||||
val configName = trimmedLine.removePrefix("# ").removeSuffix(" is not set")
|
|
||||||
if (configName.startsWith("CONFIG_")) {
|
|
||||||
configMap[configName] = "not_set"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 处理其他类型的配置项 CONFIG_XXX=value
|
|
||||||
trimmedLine.contains("=") && trimmedLine.startsWith("CONFIG_") -> {
|
|
||||||
val parts = trimmedLine.split("=", limit = 2)
|
|
||||||
if (parts.size == 2) {
|
|
||||||
configMap[parts[0]] = parts[1]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
e.printStackTrace()
|
|
||||||
}
|
|
||||||
configMap
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 从assets复制ksu_susfs文件到/data/adb/ksu/bin/
|
* 从assets复制ksu_susfs文件到/data/adb/ksu/bin/
|
||||||
*/
|
*/
|
||||||
@@ -785,63 +716,14 @@ object SuSFSManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取功能配置映射表
|
* 获取SuSFS启用功能状态
|
||||||
*/
|
|
||||||
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"),
|
|
||||||
FeatureMapping("status_sus_su", "CONFIG_KSU_SUSFS_SUS_SU")
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取启用功能状态
|
|
||||||
*/
|
*/
|
||||||
suspend fun getEnabledFeatures(context: Context): List<EnabledFeature> = withContext(Dispatchers.IO) {
|
suspend fun getEnabledFeatures(context: Context): List<EnabledFeature> = withContext(Dispatchers.IO) {
|
||||||
try {
|
try {
|
||||||
// 每次都重新执行命令获取最新状态
|
val susfsStatus = Natives.getSusfsFeatureStatus()
|
||||||
val shell = getRootShell()
|
if (susfsStatus != null) {
|
||||||
val targetPath = getSuSFSTargetPath()
|
parseEnabledFeaturesFromStatus(context, susfsStatus)
|
||||||
|
|
||||||
// 首先检查二进制文件是否存在于目标位置
|
|
||||||
val checkResult = shell.newJob().add("test -f '$targetPath'").exec()
|
|
||||||
|
|
||||||
val binaryPath = if (checkResult.isSuccess) {
|
|
||||||
// 如果目标位置存在,直接使用
|
|
||||||
targetPath
|
|
||||||
} else {
|
} 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)
|
|
||||||
|
|
||||||
// 读取/proc/config.gz进行二次检查
|
|
||||||
val procConfig = readProcConfig()
|
|
||||||
|
|
||||||
if (output.isNotEmpty()) {
|
|
||||||
parseEnabledFeatures(context, output, procConfig)
|
|
||||||
} else {
|
|
||||||
// 如果命令输出为空,返回空列表
|
|
||||||
emptyList()
|
emptyList()
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
@@ -851,65 +733,35 @@ object SuSFSManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 解析启用功能状态输出
|
* 解析SuSFS启用功能状态
|
||||||
*/
|
*/
|
||||||
private fun parseEnabledFeatures(context: Context, output: String, procConfig: Map<String, String>): List<EnabledFeature> {
|
private fun parseEnabledFeaturesFromStatus(context: Context, status: Natives.SusfsFeatureStatus): List<EnabledFeature> {
|
||||||
val features = mutableListOf<EnabledFeature>()
|
val features = mutableListOf<EnabledFeature>()
|
||||||
|
|
||||||
// 将输出按行分割并保存到集合中进行快速查找
|
// 定义功能名称和状态的映射
|
||||||
val outputLines = output.lines().map { it.trim() }.filter { it.isNotEmpty() }.toSet()
|
val featureList = listOf(
|
||||||
|
Triple("status_sus_path", context.getString(R.string.sus_path_feature_label), status.statusSusPath),
|
||||||
// 获取功能配置映射表
|
Triple("status_sus_mount", context.getString(R.string.sus_mount_feature_label), status.statusSusMount),
|
||||||
val featureMappings = getFeatureMappings()
|
Triple("status_try_umount", context.getString(R.string.try_umount_feature_label), status.statusTryUmount),
|
||||||
|
Triple("status_spoof_uname", context.getString(R.string.spoof_uname_feature_label), status.statusSpoofUname),
|
||||||
// 定义功能名称映射(id到显示名称)
|
Triple("status_spoof_cmdline", context.getString(R.string.spoof_cmdline_feature_label), status.statusSpoofCmdline),
|
||||||
val featureNameMap = mapOf(
|
Triple("status_open_redirect", context.getString(R.string.open_redirect_feature_label), status.statusOpenRedirect),
|
||||||
"status_sus_path" to context.getString(R.string.sus_path_feature_label),
|
Triple("status_enable_log", context.getString(R.string.enable_log_feature_label), status.statusEnableLog),
|
||||||
"status_sus_mount" to context.getString(R.string.sus_mount_feature_label),
|
Triple("status_auto_default_mount", context.getString(R.string.auto_default_mount_feature_label), status.statusAutoDefaultMount),
|
||||||
"status_try_umount" to context.getString(R.string.try_umount_feature_label),
|
Triple("status_auto_bind_mount", context.getString(R.string.auto_bind_mount_feature_label), status.statusAutoBindMount),
|
||||||
"status_spoof_uname" to context.getString(R.string.spoof_uname_feature_label),
|
Triple("status_auto_try_umount_bind", context.getString(R.string.auto_try_umount_bind_feature_label), status.statusAutoTryUmountBind),
|
||||||
"status_spoof_cmdline" to context.getString(R.string.spoof_cmdline_feature_label),
|
Triple("status_hide_symbols", context.getString(R.string.hide_symbols_feature_label), status.statusHideSymbols),
|
||||||
"status_open_redirect" to context.getString(R.string.open_redirect_feature_label),
|
Triple("status_sus_kstat", context.getString(R.string.sus_kstat_feature_label), status.statusSusKstat),
|
||||||
"status_enable_log" to context.getString(R.string.enable_log_feature_label),
|
Triple("status_magic_mount", context.getString(R.string.magic_mount_feature_label), status.statusMagicMount),
|
||||||
"status_auto_default_mount" to context.getString(R.string.auto_default_mount_feature_label),
|
Triple("status_overlayfs_auto_kstat", context.getString(R.string.overlayfs_auto_kstat_feature_label), status.statusOverlayfsAutoKstat),
|
||||||
"status_auto_bind_mount" to context.getString(R.string.auto_bind_mount_feature_label),
|
Triple("status_sus_su", context.getString(R.string.sus_su_feature_label), status.statusSusSu)
|
||||||
"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),
|
|
||||||
"status_sus_su" to context.getString(R.string.sus_su_feature_label)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// 根据映射表检查每个功能的启用状态
|
// 根据功能列表创建EnabledFeature对象
|
||||||
featureMappings.forEach { mapping ->
|
featureList.forEach { (id, displayName, isEnabled) ->
|
||||||
val displayName = featureNameMap[mapping.id] ?: mapping.id
|
|
||||||
|
|
||||||
// 检查show enabled_features命令输出中是否存在该配置
|
|
||||||
val existsInOutput = outputLines.contains(mapping.config)
|
|
||||||
|
|
||||||
// 检查/proc/config.gz中的配置状态
|
|
||||||
val procConfigValue = procConfig[mapping.config]
|
|
||||||
|
|
||||||
val isEnabled = when {
|
|
||||||
// 如果show enabled_features命令中存在该CONFIG,则认为启用
|
|
||||||
existsInOutput -> true
|
|
||||||
|
|
||||||
// 如果show enabled_features命令中不存在该CONFIG,则检查/proc/config.gz中是否存在y
|
|
||||||
!existsInOutput && procConfigValue == "y" -> true
|
|
||||||
|
|
||||||
// 如果/proc/config.gz中对应的为is not set,则为未启用
|
|
||||||
procConfigValue == "not_set" -> false
|
|
||||||
|
|
||||||
// 如果/proc/config.gz中没有对应的CONFIG,则按照show enabled_features命令为主
|
|
||||||
procConfigValue == null -> false
|
|
||||||
|
|
||||||
else -> false
|
|
||||||
}
|
|
||||||
|
|
||||||
val statusText = if (isEnabled) context.getString(R.string.susfs_feature_enabled) else context.getString(R.string.susfs_feature_disabled)
|
val statusText = if (isEnabled) context.getString(R.string.susfs_feature_enabled) else context.getString(R.string.susfs_feature_disabled)
|
||||||
// 只有 enable_log 功能可以配置
|
// 只有对应功能可以配置
|
||||||
val canConfigure = mapping.id == "status_enable_log"
|
val canConfigure = id == "status_enable_log"
|
||||||
features.add(EnabledFeature(displayName, isEnabled, statusText, canConfigure))
|
features.add(EnabledFeature(displayName, isEnabled, statusText, canConfigure))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user