manager: refine flashing module utilities

This commit is contained in:
weishu
2025-02-20 20:56:21 +08:00
parent eeffecbd1b
commit 107a34789e
3 changed files with 52 additions and 39 deletions

View File

@@ -53,9 +53,10 @@ import kotlinx.coroutines.withContext
import kotlinx.parcelize.Parcelize import kotlinx.parcelize.Parcelize
import me.weishu.kernelsu.R import me.weishu.kernelsu.R
import me.weishu.kernelsu.ui.component.KeyEventBlocker import me.weishu.kernelsu.ui.component.KeyEventBlocker
import me.weishu.kernelsu.ui.util.FlashResult
import me.weishu.kernelsu.ui.util.LkmSelection import me.weishu.kernelsu.ui.util.LkmSelection
import me.weishu.kernelsu.ui.util.LocalSnackbarHost import me.weishu.kernelsu.ui.util.LocalSnackbarHost
import me.weishu.kernelsu.ui.util.flashModule import me.weishu.kernelsu.ui.util.flashModules
import me.weishu.kernelsu.ui.util.installBoot import me.weishu.kernelsu.ui.util.installBoot
import me.weishu.kernelsu.ui.util.reboot import me.weishu.kernelsu.ui.util.reboot
import me.weishu.kernelsu.ui.util.restoreBoot import me.weishu.kernelsu.ui.util.restoreBoot
@@ -98,16 +99,7 @@ fun FlashScreen(navigator: DestinationsNavigator, flashIt: FlashIt) {
return@LaunchedEffect return@LaunchedEffect
} }
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
flashIt(flashIt, onFinish = { showReboot, code -> flashIt(flashIt, onStdout = {
if (code != 0) {
text += "Error: exit code = $code.\nPlease save and check the log.\n"
}
if (showReboot) {
text += "\n\n\n"
showFloatAction = true
}
flashing = if (code == 0) FlashingStatus.SUCCESS else FlashingStatus.FAILED
}, onStdout = {
tempText = "$it\n" tempText = "$it\n"
if (tempText.startsWith("")) { // clear command if (tempText.startsWith("")) { // clear command
text = tempText.substring(6) text = tempText.substring(6)
@@ -117,7 +109,16 @@ fun FlashScreen(navigator: DestinationsNavigator, flashIt: FlashIt) {
logContent.append(it).append("\n") logContent.append(it).append("\n")
}, onStderr = { }, onStderr = {
logContent.append(it).append("\n") logContent.append(it).append("\n")
}) }).apply {
if (code != 0) {
text += "Error code: $code.\n $err Please save and check the log.\n"
}
if (showReboot) {
text += "\n\n\n"
showFloatAction = true
}
flashing = if (code == 0) FlashingStatus.SUCCESS else FlashingStatus.FAILED
}
} }
} }
@@ -191,7 +192,7 @@ sealed class FlashIt : Parcelable {
data class FlashBoot(val boot: Uri? = null, val lkm: LkmSelection, val ota: Boolean) : data class FlashBoot(val boot: Uri? = null, val lkm: LkmSelection, val ota: Boolean) :
FlashIt() FlashIt()
data class FlashModule(val uri: Uri) : FlashIt() data class FlashModules(val uri: List<Uri>) : FlashIt()
data object FlashRestore : FlashIt() data object FlashRestore : FlashIt()
@@ -199,25 +200,24 @@ sealed class FlashIt : Parcelable {
} }
fun flashIt( fun flashIt(
flashIt: FlashIt, onFinish: (Boolean, Int) -> Unit, flashIt: FlashIt,
onStdout: (String) -> Unit, onStdout: (String) -> Unit,
onStderr: (String) -> Unit onStderr: (String) -> Unit
) { ): FlashResult {
when (flashIt) { return when (flashIt) {
is FlashIt.FlashBoot -> installBoot( is FlashIt.FlashBoot -> installBoot(
flashIt.boot, flashIt.boot,
flashIt.lkm, flashIt.lkm,
flashIt.ota, flashIt.ota,
onFinish,
onStdout, onStdout,
onStderr onStderr
) )
is FlashIt.FlashModule -> flashModule(flashIt.uri, onFinish, onStdout, onStderr) is FlashIt.FlashModules -> flashModules(flashIt.uri, onStdout, onStderr)
FlashIt.FlashRestore -> restoreBoot(onFinish, onStdout, onStderr) FlashIt.FlashRestore -> restoreBoot(onStdout, onStderr)
FlashIt.FlashUninstall -> uninstallPermanently(onFinish, onStdout, onStderr) FlashIt.FlashUninstall -> uninstallPermanently(onStdout, onStderr)
} }
} }

View File

@@ -209,7 +209,7 @@ fun ModuleScreen(navigator: DestinationsNavigator) {
val data = it.data ?: return@rememberLauncherForActivityResult val data = it.data ?: return@rememberLauncherForActivityResult
val uri = data.data ?: return@rememberLauncherForActivityResult val uri = data.data ?: return@rememberLauncherForActivityResult
navigator.navigate(FlashScreenDestination(FlashIt.FlashModule(uri))) navigator.navigate(FlashScreenDestination(FlashIt.FlashModules(listOf(uri))))
viewModel.markNeedRefresh() viewModel.markNeedRefresh()
@@ -254,7 +254,7 @@ fun ModuleScreen(navigator: DestinationsNavigator) {
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
boxModifier = Modifier.padding(innerPadding), boxModifier = Modifier.padding(innerPadding),
onInstallModule = { onInstallModule = {
navigator.navigate(FlashScreenDestination(FlashIt.FlashModule(it))) navigator.navigate(FlashScreenDestination(FlashIt.FlashModules(listOf(it))))
}, },
onClickModule = { id, name, hasWebUi -> onClickModule = { id, name, hasWebUi ->
if (hasWebUi) { if (hasWebUi) {

View File

@@ -33,6 +33,11 @@ private fun getKsuDaemonPath(): String {
return ksuApp.applicationInfo.nativeLibraryDir + File.separator + "libksud.so" return ksuApp.applicationInfo.nativeLibraryDir + File.separator + "libksud.so"
} }
data class FlashResult(val code: Int, val err: String, val showReboot: Boolean) {
constructor(result: Shell.Result, showReboot: Boolean) : this(result.code, result.err.joinToString("\n"), showReboot)
constructor(result: Shell.Result) : this(result, result.isSuccess)
}
object KsuCli { object KsuCli {
val SHELL: Shell = createRootShell() val SHELL: Shell = createRootShell()
val GLOBAL_MNT_SHELL: Shell = createRootShell(true) val GLOBAL_MNT_SHELL: Shell = createRootShell(true)
@@ -167,10 +172,9 @@ private fun flashWithIO(
fun flashModule( fun flashModule(
uri: Uri, uri: Uri,
onFinish: (Boolean, Int) -> Unit,
onStdout: (String) -> Unit, onStdout: (String) -> Unit,
onStderr: (String) -> Unit onStderr: (String) -> Unit
): Boolean { ): FlashResult {
val resolver = ksuApp.contentResolver val resolver = ksuApp.contentResolver
with(resolver.openInputStream(uri)) { with(resolver.openInputStream(uri)) {
val file = File(ksuApp.cacheDir, "module.zip") val file = File(ksuApp.cacheDir, "module.zip")
@@ -183,11 +187,24 @@ fun flashModule(
file.delete() file.delete()
onFinish(result.isSuccess, result.code) return FlashResult(result)
return result.isSuccess
} }
} }
fun flashModules(
uris: List<Uri>,
onStdout: (String) -> Unit,
onStderr: (String) -> Unit
): FlashResult {
for (uri in uris) {
val result = flashModule(uri, onStdout, onStderr)
if (result.code != 0) {
return result
}
}
return FlashResult(0, "", true)
}
fun runModuleAction( fun runModuleAction(
moduleId: String, onStdout: (String) -> Unit, onStderr: (String) -> Unit moduleId: String, onStdout: (String) -> Unit, onStderr: (String) -> Unit
): Boolean { ): Boolean {
@@ -213,21 +230,19 @@ fun runModuleAction(
} }
fun restoreBoot( fun restoreBoot(
onFinish: (Boolean, Int) -> Unit, onStdout: (String) -> Unit, onStderr: (String) -> Unit onStdout: (String) -> Unit, onStderr: (String) -> Unit
): Boolean { ): FlashResult {
val magiskboot = File(ksuApp.applicationInfo.nativeLibraryDir, "libmagiskboot.so") val magiskboot = File(ksuApp.applicationInfo.nativeLibraryDir, "libmagiskboot.so")
val result = flashWithIO("${getKsuDaemonPath()} boot-restore -f --magiskboot $magiskboot", onStdout, onStderr) val result = flashWithIO("${getKsuDaemonPath()} boot-restore -f --magiskboot $magiskboot", onStdout, onStderr)
onFinish(result.isSuccess, result.code) return FlashResult(result)
return result.isSuccess
} }
fun uninstallPermanently( fun uninstallPermanently(
onFinish: (Boolean, Int) -> Unit, onStdout: (String) -> Unit, onStderr: (String) -> Unit onStdout: (String) -> Unit, onStderr: (String) -> Unit
): Boolean { ): FlashResult {
val magiskboot = File(ksuApp.applicationInfo.nativeLibraryDir, "libmagiskboot.so") val magiskboot = File(ksuApp.applicationInfo.nativeLibraryDir, "libmagiskboot.so")
val result = flashWithIO("${getKsuDaemonPath()} uninstall --magiskboot $magiskboot", onStdout, onStderr) val result = flashWithIO("${getKsuDaemonPath()} uninstall --magiskboot $magiskboot", onStdout, onStderr)
onFinish(result.isSuccess, result.code) return FlashResult(result)
return result.isSuccess
} }
suspend fun shrinkModules(): Boolean = withContext(Dispatchers.IO) { suspend fun shrinkModules(): Boolean = withContext(Dispatchers.IO) {
@@ -245,10 +260,9 @@ fun installBoot(
bootUri: Uri?, bootUri: Uri?,
lkm: LkmSelection, lkm: LkmSelection,
ota: Boolean, ota: Boolean,
onFinish: (Boolean, Int) -> Unit,
onStdout: (String) -> Unit, onStdout: (String) -> Unit,
onStderr: (String) -> Unit, onStderr: (String) -> Unit,
): Boolean { ): FlashResult {
val resolver = ksuApp.contentResolver val resolver = ksuApp.contentResolver
val bootFile = bootUri?.let { uri -> val bootFile = bootUri?.let { uri ->
@@ -311,8 +325,7 @@ fun installBoot(
lkmFile?.delete() lkmFile?.delete()
// if boot uri is empty, it is direct install, when success, we should show reboot button // if boot uri is empty, it is direct install, when success, we should show reboot button
onFinish(bootUri == null && result.isSuccess, result.code) return FlashResult(result, bootUri == null && result.isSuccess)
return result.isSuccess
} }
fun reboot(reason: String = "") { fun reboot(reason: String = "") {