diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Flash.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Flash.kt index 2aee6c6f..60ee3ecf 100644 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Flash.kt +++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Flash.kt @@ -48,12 +48,12 @@ import com.ramcosta.composedestinations.annotation.RootGraph import com.ramcosta.composedestinations.navigation.DestinationsNavigator import com.ramcosta.composedestinations.navigation.EmptyDestinationsNavigator import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import kotlinx.parcelize.Parcelize import me.weishu.kernelsu.R 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.LocalSnackbarHost import me.weishu.kernelsu.ui.util.flashModule @@ -70,7 +70,7 @@ import java.util.Locale * @author weishu * @date 2023/1/1. */ - + enum class FlashingStatus { FLASHING, SUCCESS, @@ -80,38 +80,17 @@ enum class FlashingStatus { // Lets you flash modules sequentially when mutiple zipUris are selected fun flashModulesSequentially( uris: List, - onFinish: (Boolean, Int) -> Unit, onStdout: (String) -> Unit, onStderr: (String) -> Unit -) { - val iterator = uris.iterator() - - // Start processing from the first module inside a coroutine - CoroutineScope(Dispatchers.IO).launch { - // Define the recursive function within the coroutine - suspend fun processNext() { - if (iterator.hasNext()) { - // Flash the current module - flashModule(iterator.next(), onFinish = { showReboot, code -> - // If successful, continue to the next one - if (code == 0) { - // Recursively call to process the next module - launch { - processNext() - } - } else { - onFinish(showReboot, code) // If failed, finish the process - } - }, onStdout, onStderr) - } else { - // No more modules to process, finish the process - onFinish(true, 0) +): FlashResult { + for (uri in uris) { + flashModule(uri, onStdout, onStderr).apply { + if (code != 0) { + return FlashResult(code, err, showReboot) } } - - // Start the process - processNext() } + return FlashResult(0, "", true) } @OptIn(ExperimentalMaterial3Api::class) @@ -120,7 +99,7 @@ fun flashModulesSequentially( fun FlashScreen(navigator: DestinationsNavigator, flashIt: FlashIt) { var text by rememberSaveable { mutableStateOf("") } - var tempText : String + var tempText: String val logContent = rememberSaveable { StringBuilder() } var showFloatAction by rememberSaveable { mutableStateOf(false) } @@ -137,16 +116,7 @@ fun FlashScreen(navigator: DestinationsNavigator, flashIt: FlashIt) { return@LaunchedEffect } withContext(Dispatchers.IO) { - flashIt(flashIt, onFinish = { showReboot, code -> - 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 = { + flashIt(flashIt, onStdout = { tempText = "$it\n" if (tempText.startsWith("")) { // clear command text = tempText.substring(6) @@ -156,7 +126,16 @@ fun FlashScreen(navigator: DestinationsNavigator, flashIt: FlashIt) { logContent.append(it).append("\n") }, onStderr = { 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 + } } } @@ -240,29 +219,28 @@ sealed class FlashIt : Parcelable { } fun flashIt( - flashIt: FlashIt, onFinish: (Boolean, Int) -> Unit, + flashIt: FlashIt, onStdout: (String) -> Unit, onStderr: (String) -> Unit -) { - when (flashIt) { +): FlashResult { + return when (flashIt) { is FlashIt.FlashBoot -> installBoot( flashIt.boot, flashIt.lkm, flashIt.ota, - onFinish, onStdout, onStderr ) - is FlashIt.FlashModule -> flashModule(flashIt.uri, onFinish, onStdout, onStderr) + is FlashIt.FlashModule -> flashModule(flashIt.uri, onStdout, onStderr) is FlashIt.FlashModules -> { - flashModulesSequentially(flashIt.uris, onFinish, onStdout, onStderr) + flashModulesSequentially(flashIt.uris, onStdout, onStderr) } - FlashIt.FlashRestore -> restoreBoot(onFinish, onStdout, onStderr) + FlashIt.FlashRestore -> restoreBoot(onStdout, onStderr) - FlashIt.FlashUninstall -> uninstallPermanently(onFinish, onStdout, onStderr) + FlashIt.FlashUninstall -> uninstallPermanently(onStdout, onStderr) } } diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/util/KsuCli.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/util/KsuCli.kt index 8b325848..ac2a58e7 100644 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/util/KsuCli.kt +++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/util/KsuCli.kt @@ -33,6 +33,11 @@ private fun getKsuDaemonPath(): String { 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 { val SHELL: Shell = createRootShell() val GLOBAL_MNT_SHELL: Shell = createRootShell(true) @@ -167,10 +172,9 @@ private fun flashWithIO( fun flashModule( uri: Uri, - onFinish: (Boolean, Int) -> Unit, onStdout: (String) -> Unit, onStderr: (String) -> Unit -): Boolean { +): FlashResult { val resolver = ksuApp.contentResolver with(resolver.openInputStream(uri)) { val file = File(ksuApp.cacheDir, "module.zip") @@ -183,8 +187,7 @@ fun flashModule( file.delete() - onFinish(result.isSuccess, result.code) - return result.isSuccess + return FlashResult(result) } } @@ -213,21 +216,19 @@ fun runModuleAction( } fun restoreBoot( - onFinish: (Boolean, Int) -> Unit, onStdout: (String) -> Unit, onStderr: (String) -> Unit -): Boolean { + onStdout: (String) -> Unit, onStderr: (String) -> Unit +): FlashResult { val magiskboot = File(ksuApp.applicationInfo.nativeLibraryDir, "libmagiskboot.so") val result = flashWithIO("${getKsuDaemonPath()} boot-restore -f --magiskboot $magiskboot", onStdout, onStderr) - onFinish(result.isSuccess, result.code) - return result.isSuccess + return FlashResult(result) } fun uninstallPermanently( - onFinish: (Boolean, Int) -> Unit, onStdout: (String) -> Unit, onStderr: (String) -> Unit -): Boolean { + onStdout: (String) -> Unit, onStderr: (String) -> Unit +): FlashResult { val magiskboot = File(ksuApp.applicationInfo.nativeLibraryDir, "libmagiskboot.so") val result = flashWithIO("${getKsuDaemonPath()} uninstall --magiskboot $magiskboot", onStdout, onStderr) - onFinish(result.isSuccess, result.code) - return result.isSuccess + return FlashResult(result) } suspend fun shrinkModules(): Boolean = withContext(Dispatchers.IO) { @@ -245,10 +246,9 @@ fun installBoot( bootUri: Uri?, lkm: LkmSelection, ota: Boolean, - onFinish: (Boolean, Int) -> Unit, onStdout: (String) -> Unit, onStderr: (String) -> Unit, -): Boolean { +): FlashResult { val resolver = ksuApp.contentResolver val bootFile = bootUri?.let { uri -> @@ -311,8 +311,7 @@ fun installBoot( lkmFile?.delete() // if boot uri is empty, it is direct install, when success, we should show reboot button - onFinish(bootUri == null && result.isSuccess, result.code) - return result.isSuccess + return FlashResult(result, bootUri == null && result.isSuccess) } fun reboot(reason: String = "") {