Skip to content

Commit

Permalink
ksud: backup stock image and use it when restore (tiann#1619)
Browse files Browse the repository at this point in the history
  • Loading branch information
5ec1cff authored Apr 13, 2024
1 parent 1be266b commit 60dd52a
Show file tree
Hide file tree
Showing 8 changed files with 244 additions and 64 deletions.
60 changes: 50 additions & 10 deletions manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Flash.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,21 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.filled.Refresh
import androidx.compose.material.icons.filled.Save
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExtendedFloatingActionButton
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.key.Key
Expand All @@ -37,9 +49,17 @@ import me.weishu.kernelsu.ui.util.LocalSnackbarHost
import me.weishu.kernelsu.ui.util.installBoot
import me.weishu.kernelsu.ui.util.installModule
import me.weishu.kernelsu.ui.util.reboot
import me.weishu.kernelsu.ui.util.restoreBoot
import java.io.File
import java.text.SimpleDateFormat
import java.util.*
import java.util.Date
import java.util.Locale

enum class FlashingStatus {
FLASHING,
SUCCESS,
FAILED
}

/**
* @author weishu
Expand All @@ -57,19 +77,24 @@ fun FlashScreen(navigator: DestinationsNavigator, flashIt: FlashIt) {
val snackBarHost = LocalSnackbarHost.current
val scope = rememberCoroutineScope()
val scrollState = rememberScrollState()
var flashing by rememberSaveable {
mutableStateOf(FlashingStatus.FLASHING)
}

LaunchedEffect(Unit) {
if (text.isNotEmpty()) {
return@LaunchedEffect
}
withContext(Dispatchers.IO) {
flashIt(flashIt, onFinish = { showReboot ->
flashIt(flashIt, onFinish = { showReboot, code ->
if (code != 0) {
text += "Error: exit code = $code.\nPlease save and check the log.\n"
}
if (showReboot) {
for (i in 0..2) {
text += "\n"
}
text += "\n\n\n"
showFloatAction = true
}
flashing = if (code == 0) FlashingStatus.SUCCESS else FlashingStatus.FAILED
}, onStdout = {
text += "$it\n"
logContent.append(it).append("\n")
Expand All @@ -82,6 +107,7 @@ fun FlashScreen(navigator: DestinationsNavigator, flashIt: FlashIt) {
Scaffold(
topBar = {
TopBar(
flashing,
onBack = {
navigator.popBackStack()
},
Expand Down Expand Up @@ -146,10 +172,12 @@ sealed class FlashIt : Parcelable {
FlashIt()

data class FlashModule(val uri: Uri) : FlashIt()

data object FlashRestore : FlashIt()
}

fun flashIt(
flashIt: FlashIt, onFinish: (Boolean) -> Unit,
flashIt: FlashIt, onFinish: (Boolean, Int) -> Unit,
onStdout: (String) -> Unit,
onStderr: (String) -> Unit
) {
Expand All @@ -164,14 +192,26 @@ fun flashIt(
)

is FlashIt.FlashModule -> installModule(flashIt.uri, onFinish, onStdout, onStderr)

FlashIt.FlashRestore -> restoreBoot(onFinish, onStdout, onStderr)
}
}

@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun TopBar(onBack: () -> Unit = {}, onSave: () -> Unit = {}) {
private fun TopBar(status: FlashingStatus, onBack: () -> Unit = {}, onSave: () -> Unit = {}) {
TopAppBar(
title = { Text(stringResource(R.string.install)) },
title = {
Text(
stringResource(
when (status) {
FlashingStatus.FLASHING -> R.string.flashing
FlashingStatus.SUCCESS -> R.string.flash_success
FlashingStatus.FAILED -> R.string.flash_failed
}
)
)
},
navigationIcon = {
IconButton(
onClick = onBack
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,11 +123,19 @@ fun InstallScreen(navigator: DestinationsNavigator) {
installMethod = method
}

Row(
Column(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
) {
(lkmSelection as? LkmSelection.LkmUri)?.let {
Text(
stringResource(
id = R.string.selected_lkm,
it.uri.lastPathSegment ?: "(file)"
)
)
}
Button(modifier = Modifier.fillMaxWidth(),
enabled = installMethod != null,
onClick = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ import me.weishu.kernelsu.ui.component.rememberConfirmDialog
import me.weishu.kernelsu.ui.component.rememberCustomDialog
import me.weishu.kernelsu.ui.component.rememberLoadingDialog
import me.weishu.kernelsu.ui.screen.destinations.AppProfileTemplateScreenDestination
import me.weishu.kernelsu.ui.screen.destinations.FlashScreenDestination
import me.weishu.kernelsu.ui.util.getBugreportFile
import me.weishu.kernelsu.ui.util.shrinkModules

Expand Down Expand Up @@ -214,7 +215,7 @@ fun SettingScreen(navigator: DestinationsNavigator) {

val lkmMode = Natives.version >= Natives.MINIMAL_SUPPORTED_KERNEL_LKM && Natives.isLkmMode
if (lkmMode) {
UninstallItem {
UninstallItem(navigator) {
loadingDialog.withLoading(it)
}
}
Expand All @@ -237,7 +238,10 @@ fun SettingScreen(navigator: DestinationsNavigator) {
}

@Composable
fun UninstallItem(withLoading: suspend (suspend () -> Unit) -> Unit) {
fun UninstallItem(
navigator: DestinationsNavigator,
withLoading: suspend (suspend () -> Unit) -> Unit
) {
val context = LocalContext.current
val scope = rememberCoroutineScope()
val uninstallConfirmDialog = rememberConfirmDialog()
Expand All @@ -255,7 +259,9 @@ fun UninstallItem(withLoading: suspend (suspend () -> Unit) -> Unit) {
when (uninstallType) {
UninstallType.TEMPORARY -> showTodo()
UninstallType.PERMANENT -> showTodo()
UninstallType.RESTORE_STOCK_IMAGE -> showTodo()
UninstallType.RESTORE_STOCK_IMAGE -> navigator.navigate(
FlashScreenDestination(FlashIt.FlashRestore)
)
UninstallType.NONE -> Unit
}
}
Expand Down
38 changes: 34 additions & 4 deletions manager/app/src/main/java/me/weishu/kernelsu/ui/util/KsuCli.kt
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,10 @@ fun uninstallModule(id: String): Boolean {
}

fun installModule(
uri: Uri, onFinish: (Boolean) -> Unit, onStdout: (String) -> Unit, onStderr: (String) -> Unit
uri: Uri,
onFinish: (Boolean, Int) -> Unit,
onStdout: (String) -> Unit,
onStderr: (String) -> Unit
): Boolean {
val resolver = ksuApp.contentResolver
with(resolver.openInputStream(uri)) {
Expand Down Expand Up @@ -137,11 +140,38 @@ fun installModule(

file.delete()

onFinish(result.isSuccess)
onFinish(result.isSuccess, result.code)
return result.isSuccess
}
}

fun restoreBoot(
onFinish: (Boolean, Int) -> Unit, onStdout: (String) -> Unit, onStderr: (String) -> Unit
): Boolean {
val shell = createRootShell()
val magiskboot = File(ksuApp.applicationInfo.nativeLibraryDir, "libmagiskboot.so")

val stdoutCallback: CallbackList<String?> = object : CallbackList<String?>() {
override fun onAddElement(s: String?) {
onStdout(s ?: "")
}
}

val stderrCallback: CallbackList<String?> = object : CallbackList<String?>() {
override fun onAddElement(s: String?) {
onStderr(s ?: "")
}
}

val result =
shell.newJob().add("${getKsuDaemonPath()} boot-restore -f --magiskboot $magiskboot")
.to(stdoutCallback, stderrCallback)
.exec()

onFinish(result.isSuccess, result.code)
return result.isSuccess
}

suspend fun shrinkModules(): Boolean = withContext(Dispatchers.IO) {
execKsud("module shrink", true)
}
Expand All @@ -157,7 +187,7 @@ fun installBoot(
bootUri: Uri?,
lkm: LkmSelection,
ota: Boolean,
onFinish: (Boolean) -> Unit,
onFinish: (Boolean, Int) -> Unit,
onStdout: (String) -> Unit,
onStderr: (String) -> Unit,
): Boolean {
Expand Down Expand Up @@ -238,7 +268,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)
onFinish(bootUri == null && result.isSuccess, result.code)
return result.isSuccess
}

Expand Down
4 changes: 4 additions & 0 deletions manager/app/src/main/res/values-zh-rCN/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -124,4 +124,8 @@
<string name="settings_uninstall_temporary_message">临时卸载 KernelSU,下次重启后恢复</string>
<string name="settings_uninstall_permanent_message">完全并永久移除 KernelSU 和所有模块</string>
<string name="settings_restore_stock_image_message">恢复原厂镜像,一般在 OTA 前使用;如需卸载请使用“永久卸载”</string>
<string name="flashing">刷写中</string>
<string name="flash_success">刷写完成</string>
<string name="flash_failed">刷写失败</string>
<string name="selected_lkm">选择的 LKM :%s</string>
</resources>
4 changes: 4 additions & 0 deletions manager/app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -126,4 +126,8 @@
<string name="settings_uninstall_temporary_message">Temporarily uninstall KernelSU, restore to original state after next reboot.</string>
<string name="settings_uninstall_permanent_message">Uninstalling KernelSU(Root and all modules) completely and permanently.</string>
<string name="settings_restore_stock_image_message">Restore the stock factory image (if a backup exists), usually used before OTA; if you need to uninstall KernelSU, please use \"Permanent Uninstall\".</string>
<string name="flashing">Flashing</string>
<string name="flash_success">Flash success</string>
<string name="flash_failed">Flash failed</string>
<string name="selected_lkm">Selected lkm: %s</string>
</resources>
Loading

0 comments on commit 60dd52a

Please sign in to comment.