Fix root detection for KernelSU
Use libsu's Shell API instead of Runtime.exec("su -c ...") for root
detection. The previous approach assumed su is in PATH, which works
for Magisk but not for KernelSU where su has a different path.
This commit is contained in:
@@ -18,16 +18,6 @@ import kotlin.coroutines.resumeWithException
|
|||||||
|
|
||||||
object RootInstaller {
|
object RootInstaller {
|
||||||
|
|
||||||
suspend fun checkAccess(): Boolean = withContext(Dispatchers.IO) {
|
|
||||||
try {
|
|
||||||
val process = Runtime.getRuntime().exec("su -c echo test")
|
|
||||||
val exitCode = process.waitFor()
|
|
||||||
exitCode == 0
|
|
||||||
} catch (e: Exception) {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun install(apkFile: File) {
|
suspend fun install(apkFile: File) {
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
bindRootService().use { handle ->
|
bindRootService().use { handle ->
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ import androidx.navigation.NavController
|
|||||||
import androidx.lifecycle.Lifecycle
|
import androidx.lifecycle.Lifecycle
|
||||||
import androidx.lifecycle.LifecycleEventObserver
|
import androidx.lifecycle.LifecycleEventObserver
|
||||||
import io.nekohasekai.sfa.R
|
import io.nekohasekai.sfa.R
|
||||||
|
import io.nekohasekai.sfa.bg.RootClient
|
||||||
import io.nekohasekai.sfa.compose.topbar.OverrideTopBar
|
import io.nekohasekai.sfa.compose.topbar.OverrideTopBar
|
||||||
import io.nekohasekai.sfa.database.Settings
|
import io.nekohasekai.sfa.database.Settings
|
||||||
import io.nekohasekai.sfa.compose.screen.profileoverride.PerAppProxyScanner
|
import io.nekohasekai.sfa.compose.screen.profileoverride.PerAppProxyScanner
|
||||||
@@ -206,18 +207,7 @@ fun ProfileOverrideScreen(navController: NavController) {
|
|||||||
onCheckedChange = { checked ->
|
onCheckedChange = { checked ->
|
||||||
if (checked && !autoRedirect) {
|
if (checked && !autoRedirect) {
|
||||||
scope.launch {
|
scope.launch {
|
||||||
val hasRoot =
|
val hasRoot = RootClient.checkRootAvailable()
|
||||||
withContext(Dispatchers.IO) {
|
|
||||||
try {
|
|
||||||
val process = Runtime.getRuntime().exec("su -c id")
|
|
||||||
process.inputStream.close()
|
|
||||||
process.outputStream.close()
|
|
||||||
process.errorStream.close()
|
|
||||||
process.waitFor() == 0
|
|
||||||
} catch (e: Exception) {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (hasRoot) {
|
if (hasRoot) {
|
||||||
autoRedirect = true
|
autoRedirect = true
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package io.nekohasekai.sfa.vendor
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import io.nekohasekai.sfa.Application
|
import io.nekohasekai.sfa.Application
|
||||||
import io.nekohasekai.sfa.bg.BoxService
|
import io.nekohasekai.sfa.bg.BoxService
|
||||||
|
import io.nekohasekai.sfa.bg.RootClient
|
||||||
import io.nekohasekai.sfa.database.Settings
|
import io.nekohasekai.sfa.database.Settings
|
||||||
import io.nekohasekai.sfa.utils.HookStatusClient
|
import io.nekohasekai.sfa.utils.HookStatusClient
|
||||||
import io.nekohasekai.sfa.xposed.XposedActivation
|
import io.nekohasekai.sfa.xposed.XposedActivation
|
||||||
@@ -62,7 +63,7 @@ object ApkInstaller {
|
|||||||
return when (method) {
|
return when (method) {
|
||||||
InstallMethod.PACKAGE_INSTALLER -> canSystemSilentInstall()
|
InstallMethod.PACKAGE_INSTALLER -> canSystemSilentInstall()
|
||||||
InstallMethod.SHIZUKU -> ShizukuInstaller.isAvailable() && ShizukuInstaller.checkPermission()
|
InstallMethod.SHIZUKU -> ShizukuInstaller.isAvailable() && ShizukuInstaller.checkPermission()
|
||||||
InstallMethod.ROOT -> RootInstaller.checkAccess()
|
InstallMethod.ROOT -> RootClient.checkRootAvailable()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import androidx.camera.core.ImageAnalysis
|
|||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import io.nekohasekai.sfa.Application
|
import io.nekohasekai.sfa.Application
|
||||||
import io.nekohasekai.sfa.R
|
import io.nekohasekai.sfa.R
|
||||||
|
import io.nekohasekai.sfa.bg.RootClient
|
||||||
import io.nekohasekai.sfa.database.Settings
|
import io.nekohasekai.sfa.database.Settings
|
||||||
import io.nekohasekai.sfa.compose.screen.qrscan.QRCodeCropArea
|
import io.nekohasekai.sfa.compose.screen.qrscan.QRCodeCropArea
|
||||||
import io.nekohasekai.sfa.update.UpdateCheckException
|
import io.nekohasekai.sfa.update.UpdateCheckException
|
||||||
@@ -135,7 +136,7 @@ object Vendor : VendorInterface {
|
|||||||
}
|
}
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
"ROOT" -> RootInstaller.checkAccess()
|
"ROOT" -> RootClient.checkRootAvailable()
|
||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package io.nekohasekai.sfa.vendor
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import io.nekohasekai.sfa.Application
|
import io.nekohasekai.sfa.Application
|
||||||
|
import io.nekohasekai.sfa.bg.RootClient
|
||||||
import io.nekohasekai.sfa.database.Settings
|
import io.nekohasekai.sfa.database.Settings
|
||||||
import io.nekohasekai.sfa.utils.HookStatusClient
|
import io.nekohasekai.sfa.utils.HookStatusClient
|
||||||
import io.nekohasekai.sfa.xposed.XposedActivation
|
import io.nekohasekai.sfa.xposed.XposedActivation
|
||||||
@@ -43,7 +44,7 @@ object ApkInstaller {
|
|||||||
val method = getConfiguredMethod()
|
val method = getConfiguredMethod()
|
||||||
return when (method) {
|
return when (method) {
|
||||||
InstallMethod.PACKAGE_INSTALLER -> canSystemSilentInstall()
|
InstallMethod.PACKAGE_INSTALLER -> canSystemSilentInstall()
|
||||||
InstallMethod.ROOT -> RootInstaller.checkAccess()
|
InstallMethod.ROOT -> RootClient.checkRootAvailable()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import androidx.camera.core.ImageAnalysis
|
|||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import io.nekohasekai.sfa.Application
|
import io.nekohasekai.sfa.Application
|
||||||
import io.nekohasekai.sfa.R
|
import io.nekohasekai.sfa.R
|
||||||
|
import io.nekohasekai.sfa.bg.RootClient
|
||||||
import io.nekohasekai.sfa.database.Settings
|
import io.nekohasekai.sfa.database.Settings
|
||||||
import io.nekohasekai.sfa.compose.screen.qrscan.QRCodeCropArea
|
import io.nekohasekai.sfa.compose.screen.qrscan.QRCodeCropArea
|
||||||
import io.nekohasekai.sfa.update.UpdateCheckException
|
import io.nekohasekai.sfa.update.UpdateCheckException
|
||||||
@@ -125,7 +126,7 @@ object Vendor : VendorInterface {
|
|||||||
"PACKAGE_INSTALLER" -> {
|
"PACKAGE_INSTALLER" -> {
|
||||||
ApkInstaller.canSystemSilentInstall()
|
ApkInstaller.canSystemSilentInstall()
|
||||||
}
|
}
|
||||||
"ROOT" -> RootInstaller.checkAccess()
|
"ROOT" -> RootClient.checkRootAvailable()
|
||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user