Skip to content

Commit

Permalink
lazy initial sdless impl (missing parttool, create & update flows)
Browse files Browse the repository at this point in the history
  • Loading branch information
nift4 committed Aug 26, 2024
1 parent 1ce0334 commit 0a838f7
Show file tree
Hide file tree
Showing 12 changed files with 158 additions and 46 deletions.
35 changes: 22 additions & 13 deletions app/src/main/java/org/andbootmgr/app/BackupRestoreFlow.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ import org.andbootmgr.app.util.SDUtils
import java.io.File
import java.io.IOException

class BackupRestoreFlow(private val partitionId: Int): WizardFlow() {
class BackupRestoreFlow(private val partitionId: Int, private val partFile: File?): WizardFlow() {
override fun get(vm: WizardState): List<IWizardPage> {
val c = CreateBackupDataHolder(vm, partitionId)
val c = CreateBackupDataHolder(vm, partitionId, partFile)
return listOf(WizardPage("start",
NavButton(vm.activity.getString(R.string.cancel)) { it.finish() },
NavButton("") {})
Expand All @@ -44,22 +44,26 @@ class BackupRestoreFlow(private val partitionId: Int): WizardFlow() {
}
}

private class CreateBackupDataHolder(val vm: WizardState, val pi: Int) {
private class CreateBackupDataHolder(val vm: WizardState, val pi: Int?, val partFile: File?) {
var action: Int = 0
var path: Uri? = null
var meta: SDUtils.SDPartitionMeta? = null
}

@Composable
private fun ChooseAction(c: CreateBackupDataHolder) {
LaunchedEffect(Unit) {
c.meta = SDUtils.generateMeta(c.vm.deviceInfo)
if (c.vm.deviceInfo.metaonsd) {
LaunchedEffect(Unit) {
c.meta = SDUtils.generateMeta(c.vm.deviceInfo)
}
}

Column(horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center,
modifier = Modifier.fillMaxSize()
) {
Text(stringResource(id = R.string.backup_msg, c.meta!!.dumpKernelPartition(c.pi).name), textAlign = TextAlign.Center)
val name = if (c.vm.deviceInfo.metaonsd)
c.meta!!.dumpKernelPartition(c.pi!!).name else c.partFile!!.name
Text(stringResource(id = R.string.backup_msg, name), textAlign = TextAlign.Center)
Button(onClick = { c.action=1; c.vm.navigate("select") }) {
Text(stringResource(R.string.backup))
}
Expand Down Expand Up @@ -93,6 +97,8 @@ private fun SelectDroidBoot(c: CreateBackupDataHolder) {
}
)
Button(onClick = {
val name = if (c.vm.deviceInfo.metaonsd)
c.meta!!.dumpKernelPartition(c.pi!!).name else c.partFile!!.nameWithoutExtension
if (c.action != 1) {
c.vm.activity.chooseFile("*/*") {
c.vm.chosen["file"] = WizardState.DownloadedFile(it, null)
Expand All @@ -101,7 +107,7 @@ private fun SelectDroidBoot(c: CreateBackupDataHolder) {
c.vm.onNext = { i -> i.navigate("go") }
}
} else {
c.vm.activity.createFile("${c.meta!!.dumpKernelPartition(c.pi).name}.img") {
c.vm.activity.createFile("${name}.img") {
c.path = it
nextButtonAvailable = true
c.vm.nextText = c.vm.activity.getString(R.string.next)
Expand All @@ -120,25 +126,28 @@ private fun Flash(c: CreateBackupDataHolder) {
WizardTerminalWork(c.vm, logFile = "flash_${System.currentTimeMillis()}.txt") { terminal ->
c.vm.logic.extractToolkit(terminal)
terminal.add(c.vm.activity.getString(R.string.term_starting))
val p = c.meta!!.dumpKernelPartition(c.pi)
if (!c.vm.logic.unmount(p).to(terminal).exec().isSuccess)
throw IOException(c.vm.activity.getString(R.string.term_cant_umount))
val path = if (c.vm.deviceInfo.metaonsd) {
val p = c.meta!!.dumpKernelPartition(c.pi!!)
if (!c.vm.logic.unmount(p).to(terminal).exec().isSuccess)
throw IOException(c.vm.activity.getString(R.string.term_cant_umount))
p.path
} else c.partFile!!.absolutePath
if (c.action == 1) {
c.vm.copy(
SuFileInputStream.open(File(p.path)),
SuFileInputStream.open(path),
c.vm.activity.contentResolver.openOutputStream(c.path!!)!!
)
} else if (c.action == 2) {
c.vm.copyPriv(
c.vm.chosen["file"]!!.openInputStream(c.vm),
File(p.path)
File(path)
)
} else if (c.action == 3) {
val result2 = Shell.cmd(
File(
c.vm.logic.toolkitDir,
"simg2img"
).absolutePath + " ${c.vm.chosen["file"]!!.toFile(c.vm).absolutePath} ${p.path}"
).absolutePath + " ${c.vm.chosen["file"]!!.toFile(c.vm).absolutePath} $path"
).to(terminal).exec()
if (!result2.isSuccess) {
terminal.add(c.vm.activity.getString(R.string.term_failure))
Expand Down
8 changes: 4 additions & 4 deletions app/src/main/java/org/andbootmgr/app/CreatePartFlow.kt
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ private fun Start(c: CreatePartDataHolder) {
LaunchedEffect(Unit) {
if (c.meta == null) {
withContext(Dispatchers.IO) {
val meta = SDUtils.generateMeta(c.vm.deviceInfo)!!
val meta = SDUtils.generateMeta(c.vm.deviceInfo)!! // TODO !metaonsd
c.p =
meta.s.find { c.desiredStartSector == it.startSector } as SDUtils.Partition.FreeSpace
c.meta = meta
Expand Down Expand Up @@ -663,12 +663,12 @@ private fun Flash(c: CreatePartDataHolder) {
tmpFile.setExecutable(true)
terminal.add(vm.activity.getString(R.string.term_creating_pt))

vm.logic.unmountBootset()
vm.logic.unmountBootset(vm.deviceInfo)
val startSectorAbsolute = c.p.startSector + c.startSectorRelative
val endSectorAbsolute = c.p.startSector + c.endSectorRelative
if (endSectorAbsolute > c.p.endSector)
throw IllegalArgumentException("$endSectorAbsolute can't be bigger than ${c.p.endSector}")
c.parts.forEachIndexed { index, part ->
c.parts.forEachIndexed { index, part -> // TODO !metaonsd
terminal.add(vm.activity.getString(R.string.term_create_part))
val start = c.p.startSector.coerceAtLeast(startSectorAbsolute)
val end = c.p.endSector.coerceAtMost(endSectorAbsolute)
Expand Down Expand Up @@ -765,7 +765,7 @@ private fun Flash(c: CreatePartDataHolder) {
terminal.add(vm.activity.getString(R.string.term_success))
} else { // Portable partition
terminal.add(vm.activity.getString(R.string.term_create_part))
vm.logic.unmountBootset()
vm.logic.unmountBootset(vm.deviceInfo)
val r = vm.logic.create(c.p,
c.startSectorRelative,
c.endSectorRelative,
Expand Down
13 changes: 13 additions & 0 deletions app/src/main/java/org/andbootmgr/app/DeviceInfo.kt
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,19 @@ abstract class MetaOnSdDeviceInfo : DeviceInfo {
override fun isCorrupt(logic: DeviceLogic): Boolean {
return !SuFile.open(logic.abmDb, "db.conf").exists()
}
override fun getAbmSettings(logic: DeviceLogic): String? {
return logic.dmPath.absolutePath
}
}

abstract class SdLessDeviceInfo : DeviceInfo {
override val metaonsd = false
override fun isInstalled(logic: DeviceLogic): Boolean {
return SuFile.open(logic.abmSdLessBootsetImg.toURI()).exists()
}
override fun isCorrupt(logic: DeviceLogic): Boolean {
return !SuFile.open(logic.abmDb, "db.conf").exists()
}
override fun getAbmSettings(logic: DeviceLogic): String? {
if (SuFile.open(bdev).exists())
SDUtils.generateMeta(this)?.let { meta ->
Expand Down
26 changes: 25 additions & 1 deletion app/src/main/java/org/andbootmgr/app/DeviceLogic.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@ class DeviceLogic(private val ctx: Context) {
val toolkitDir = File(toolkit.targetPath, "Toolkit") // will occasionally be pruned by OS, but it's fine
private val rootTmpDir = File("/data/local/tmp")
val abmBootset = File(rootTmpDir, ".abm_bootset")
val abmSdLessBootset = File("/data/abm")
val abmSdLessBootsetImg = File(abmSdLessBootset, "bootset.img")
private val metadata = File("/metadata")
val metadataMap = File(metadata, "bootset.map")
val dmBase = File("/dev/block/mapper")
val dmName = "abmbootset"
val dmPath = File(dmBase, dmName)
val abmDb = File(abmBootset, "db")
val abmEntries = File(abmDb, "entries")
val abmDbConf = File(abmDb, "db.conf")
Expand All @@ -25,6 +32,7 @@ class DeviceLogic(private val ctx: Context) {
val ast = d.getAbmSettings(this) ?: return false
val bootsetSu = SuFile.open(abmBootset.toURI())
if (!bootsetSu.exists()) bootsetSu.mkdir()
if (!d.metaonsd && !mapBootset()) return false
val result = Shell
.cmd("mount $ast ${abmBootset.absolutePath}")
.exec()
Expand All @@ -42,7 +50,7 @@ class DeviceLogic(private val ctx: Context) {
mounted = true
return true
}
fun unmountBootset(): Boolean {
fun unmountBootset(d: DeviceInfo): Boolean {
if (!checkMounted()) return true
val result = Shell.cmd("umount ${abmBootset.absolutePath}").exec()
if (!result.isSuccess) {
Expand All @@ -56,6 +64,7 @@ class DeviceLogic(private val ctx: Context) {
Log.e("ABM_UMOUNT", out)
return !mounted
}
if (!d.metaonsd) unmapBootset()
mounted = false
return true
}
Expand All @@ -67,6 +76,21 @@ class DeviceLogic(private val ctx: Context) {
}
return mounted
}
private fun mapBootset(): Boolean {
if (SuFile.open(dmPath.toURI()).exists())
return true
val tempFile = File(cacheDir, "${System.currentTimeMillis()}.txt")
if (!Shell.cmd(File(toolkitDir, "droidboot_map_to_dm")
.absolutePath + " " + metadataMap.absolutePath + " " + tempFile.absolutePath
).exec().isSuccess) {
return false
}
return Shell.cmd("dmsetup create $dmName ${tempFile.absolutePath}").exec().isSuccess
}
private fun unmapBootset() {
if (SuFile.open(dmPath.toURI()).exists())
Shell.cmd("dmsetup remove -f --retry $dmName").exec()
}
fun mount(p: SDUtils.Partition): Shell.Job {
return Shell.cmd(p.mount())
}
Expand Down
70 changes: 56 additions & 14 deletions app/src/main/java/org/andbootmgr/app/DroidBootFlow.kt
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,8 @@ private fun Start(vm: WizardState) {

// shared across DroidBootFlow, UpdateDroidBootFlow, FixDroidBootFlow
@Composable
fun LoadDroidBootJson(vm: WizardState, content: @Composable () -> Unit) {
var loading by remember { mutableStateOf(!vm.deviceInfo.isBooted(vm.logic) || vm.deviceInfo.postInstallScript) }
fun LoadDroidBootJson(vm: WizardState, update: Boolean, content: @Composable () -> Unit) {
var loading by remember { mutableStateOf(!vm.deviceInfo.isBooted(vm.logic) || vm.deviceInfo.postInstallScript || update) }
var error by remember { mutableStateOf(false) }
LaunchedEffect(Unit) {
if (!loading) return@LaunchedEffect
Expand All @@ -101,14 +101,16 @@ fun LoadDroidBootJson(vm: WizardState, content: @Composable () -> Unit) {
val json = JSONTokener(jsonText).nextValue() as JSONObject
if (BuildConfig.VERSION_CODE < json.getInt("minAppVersion"))
throw IllegalStateException("please upgrade app")
if (!vm.deviceInfo.isBooted(vm.logic)) {
if ((!vm.deviceInfo.isBooted(vm.logic) || update) && json.has("bootloader")) {
val bl = json.getJSONObject("bootloader")
val url = bl.getString("url")
val sha = bl.getStringOrNull("sha256")
vm.inetAvailable["droidboot"] = WizardState.Downloadable(
url, sha, vm.activity.getString(R.string.droidboot_online)
)
vm.idNeeded.add("droidboot")
if (!bl.optBoolean("updateOnly", false) || update) {
val url = bl.getString("url")
val sha = bl.getStringOrNull("sha256")
vm.inetAvailable["droidboot"] = WizardState.Downloadable(
url, sha, vm.activity.getString(R.string.droidboot_online)
)
vm.idNeeded.add("droidboot")
}
}
if (vm.deviceInfo.postInstallScript) {
val i = json.getJSONObject("installScript")
Expand Down Expand Up @@ -140,7 +142,11 @@ fun LoadDroidBootJson(vm: WizardState, content: @Composable () -> Unit) {

@Composable
private fun Input(d: DroidBootFlowDataHolder) {
LoadDroidBootJson(d.vm) {
LoadDroidBootJson(d.vm, false) {
if (!d.vm.deviceInfo.isBooted(d.vm.logic) && !d.vm.idNeeded.contains("droidboot")) {
Text(stringResource(R.string.install_bl_first))
return@LoadDroidBootJson
}
Column(
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center,
Expand Down Expand Up @@ -241,7 +247,43 @@ private fun Flash(d: DroidBootFlowDataHolder) {
return@WizardTerminalWork
}
} else {
// TODO provision for sdless
if (!SuFile.open(vm.logic.abmSdLessBootset.toURI()).exists()) {
if (!SuFile.open(vm.logic.abmSdLessBootset.toURI()).mkdir()) {
terminal.add(vm.activity.getString(R.string.term_cant_create_bootset))
return@WizardTerminalWork
}
}
val bytes = 4L * 1024L * 1024L * 1024L // 4 GB for now
if (!Shell.cmd("fallocate -l $bytes" +
vm.logic.abmSdLessBootsetImg.absolutePath).to(terminal).exec().isSuccess) {
terminal.add(vm.activity.getString(R.string.term_failed_fallocate))
return@WizardTerminalWork
}
if (!Shell.cmd("uncrypt ${vm.logic.abmSdLessBootsetImg.absolutePath} " +
vm.logic.metadataMap.absolutePath).to(terminal).exec().isSuccess) {
terminal.add(vm.activity.getString(R.string.term_failed_uncrypt))
return@WizardTerminalWork
}
val tempFile = File(vm.logic.cacheDir, "${System.currentTimeMillis()}.txt")
if (!Shell.cmd(File(vm.logic.toolkitDir, "droidboot_map_to_dm")
.absolutePath + " " + vm.logic.metadataMap.absolutePath + " " + tempFile.absolutePath
).to(terminal).exec().isSuccess) {
terminal.add(vm.activity.getString(R.string.term_failed_mapconv))
return@WizardTerminalWork
}
if (SuFile.open(vm.logic.dmPath.toURI()).exists()) {
if (!Shell.cmd("dmsetup remove --retry ${vm.logic.dmName}")
.to(terminal).exec().isSuccess
) {
terminal.add(vm.activity.getString(R.string.term_failed_unmap))
return@WizardTerminalWork
}
}
if (!Shell.cmd("dmsetup create ${vm.logic.dmName} ${tempFile.absolutePath}")
.to(terminal).exec().isSuccess) {
terminal.add(vm.activity.getString(R.string.term_failed_map))
return@WizardTerminalWork
}
}

if (!vm.logic.mountBootset(vm.deviceInfo)) {
Expand All @@ -256,14 +298,14 @@ private fun Flash(d: DroidBootFlowDataHolder) {
if (!SuFile.open(vm.logic.abmDb.toURI()).exists()) {
if (!SuFile.open(vm.logic.abmDb.toURI()).mkdir()) {
terminal.add(vm.activity.getString(R.string.term_failed_create_db_dir))
vm.logic.unmountBootset()
vm.logic.unmountBootset(vm.deviceInfo)
return@WizardTerminalWork
}
}
if (!SuFile.open(vm.logic.abmEntries.toURI()).exists()) {
if (!SuFile.open(vm.logic.abmEntries.toURI()).mkdir()) {
terminal.add(vm.activity.getString(R.string.term_failed_create_entries_dir))
vm.logic.unmountBootset()
vm.logic.unmountBootset(vm.deviceInfo)
return@WizardTerminalWork
}
}
Expand Down Expand Up @@ -314,7 +356,7 @@ private fun Flash(d: DroidBootFlowDataHolder) {
tmpFile.delete()
}
terminal.add(vm.activity.getString(R.string.term_success))
vm.logic.unmountBootset()
vm.logic.unmountBootset(vm.deviceInfo)
// TODO prompt user to reboot?
}
}
8 changes: 5 additions & 3 deletions app/src/main/java/org/andbootmgr/app/FixDroidBootFlow.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import com.topjohnwu.superuser.io.SuFile
import com.topjohnwu.superuser.io.SuFileInputStream
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.io.File
import java.io.IOException

Expand All @@ -39,7 +37,11 @@ class FixDroidBootFlow: WizardFlow() {

@Composable
private fun Start(vm: WizardState) {
LoadDroidBootJson(vm) {
LoadDroidBootJson(vm, false) {
if (!vm.deviceInfo.isBooted(vm.logic) && !vm.idNeeded.contains("droidboot")) {
Text(stringResource(R.string.install_bl_first))
return@LoadDroidBootJson
}
LaunchedEffect(Unit) {
vm.nextText = vm.activity.getString(R.string.next)
vm.onNext = { it.navigate(if (vm.idNeeded.isNotEmpty()) "dload" else "flash") }
Expand Down
16 changes: 10 additions & 6 deletions app/src/main/java/org/andbootmgr/app/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -137,11 +137,11 @@ class MainActivityState(val activity: MainActivity?) {

fun unmountBootset() {
defaultCfg.clear()
logic!!.unmountBootset()
logic!!.unmountBootset(deviceInfo!!)
}

fun remountBootset() {
logic!!.unmountBootset()
logic!!.unmountBootset(deviceInfo!!)
logic!!.mountBootset(deviceInfo!!)
}
}
Expand Down Expand Up @@ -233,10 +233,6 @@ class MainActivity : ComponentActivity() {
if (Shell.cmd("mountpoint -q /data/abm/bootset").exec().isSuccess) {
Shell.cmd("umount /data/abm/bootset").exec()
}
SuFile.open("/data/abm").let {
if (it.exists())
Shell.cmd("rm -rf /data/abm").exec()
}
SuFile.open(filesDir.parentFile!!, "assets").let {
if (it.exists())
Shell.cmd("rm -rf ${filesDir.parentFile!!.resolve("assets").absolutePath}")
Expand All @@ -246,6 +242,14 @@ class MainActivity : ComponentActivity() {
// == temp migration code end ==
}
vm.deviceInfo = di.await() // blocking
// == temp migration code 2 start ==
if (vm.deviceInfo!!.metaonsd) launch {
SuFile.open("/data/abm").let {
if (it.exists())
Shell.cmd("rm -rf /data/abm").exec()
}
}
// == temp migration code 2 end ==
if (StayAliveService.instance == null) {
vm.init()
}
Expand Down
Loading

0 comments on commit 0a838f7

Please sign in to comment.