feat: move downloads to cache when unused

This allows Android to clear these files if the space is needed by the OS.
This commit is contained in:
rushiiMachine 2025-06-25 22:53:31 -07:00
parent 3e75038965
commit f8e99bad89
No known key found for this signature in database
GPG key ID: DCBE5952BB3B6420
5 changed files with 75 additions and 20 deletions

View file

@ -41,18 +41,39 @@ class PathManager(
*/
val patchingDir = context.filesDir.resolve("patching").apply { mkdirs() }
/**
* The internal app directory uses for downloads that should not be wiped,
* to be used during the patching process. When the process completes, then this
* is to be moved to the cache dir, to allow Android to wipe the downloads when
* low on storage.
*/
val patchingDownloadDir = patchingDir.resolve("downloads")
/**
* Used as a secondary location for downloads when not currently patching.
* This allows Android to clear the download cache when low on storage.
*/
val cacheDownloadDir = context.cacheDir.resolve("downloads")
/**
* A permanent location used for storing custom patching components.
* This does not get moved to an Android-managed cache dir when
* not currently patching.
*/
val customComponentsDir = patchingDir.resolve("custom")
/**
* Delete all the cache dirs and recreate them.
*/
fun clearCache() {
context.cacheDir.apply { deleteRecursively() && mkdirs() }
patchingDir.apply { deleteRecursively() && mkdirs() }
for (dir in arrayOf(patchingDir, cacheDownloadDir, context.cacheDir))
dir.deleteRecursively() && dir.mkdirs()
}
/**
* Create a new subfolder in the Discord APK cache for a specific version.
*/
fun discordApkVersionCache(version: Int): File = patchingDir
fun discordApkVersionCache(version: Int): File = patchingDownloadDir
.resolve("discord")
.resolve(version.toString())
.apply { mkdirs() }
@ -60,39 +81,39 @@ class PathManager(
/**
* Resolve a specific path for a cached injector.
*/
fun cachedInjectorDex(version: SemVer, custom: Boolean = false) = patchingDir
fun cachedInjectorDex(version: SemVer, custom: Boolean = false) = patchingDownloadDir
.resolve("injector").apply { mkdirs() }
.resolve("$version${if (custom) ".custom" else ""}.dex")
/**
* Get all the versions of custom injector builds.
*/
fun customInjectorDexs() = listCustomFiles(patchingDir.resolve("injector"))
fun customInjectorDexs() = listCustomFiles(customComponentsDir.resolve("injector"))
/**
* Resolve a specific path for a versioned cached Aliuhook build
*/
fun cachedAliuhookAAR(version: SemVer) = patchingDir
fun cachedAliuhookAAR(version: SemVer) = patchingDownloadDir
.resolve("aliuhook").apply { mkdirs() }
.resolve("$version.aar")
/**
* Resolve a specific path for a versioned smali patches archive.
*/
fun cachedSmaliPatches(version: SemVer, custom: Boolean = false) = patchingDir
fun cachedSmaliPatches(version: SemVer, custom: Boolean = false) = patchingDownloadDir
.resolve("patches").apply { mkdirs() }
.resolve("$version${if (custom) ".custom" else ""}.zip")
/**
* Get all the versions of custom smali bundles.
*/
fun customSmaliPatches() = listCustomFiles(patchingDir.resolve("patches"))
fun customSmaliPatches() = listCustomFiles(customComponentsDir.resolve("patches"))
/**
* Singular Kotlin file of the most up-to-date version
* since the stdlib is backwards compatible.
*/
fun cachedKotlinDex() = patchingDir
fun cachedKotlinDex() = patchingDownloadDir
.resolve("kotlin.dex")
/**
@ -108,7 +129,7 @@ class PathManager(
private companion object {
/**
* List all the files that follow the ```[SemVer].custom.*``` naming scheme.
* List all the files in a directory that follow SemVer naming.
*/
private fun listCustomFiles(dir: File): List<SemVer>? {
if (!dir.exists()) return null
@ -116,12 +137,9 @@ class PathManager(
val files = dir.listFiles()
?: throw Error("Failed to list directory")
val customVersions = files
return files
.map { it.nameWithoutExtension }
.filter { it.endsWith(".custom") }
.map { it.removeSuffix(".custom") }
return customVersions.mapNotNull(SemVer::parseOrNull)
.mapNotNull(SemVer::parseOrNull)
}
}
}

View file

@ -3,8 +3,7 @@ package com.aliucord.manager.patcher
import com.aliucord.manager.patcher.steps.download.*
import com.aliucord.manager.patcher.steps.install.*
import com.aliucord.manager.patcher.steps.patch.*
import com.aliucord.manager.patcher.steps.prepare.DowngradeCheckStep
import com.aliucord.manager.patcher.steps.prepare.FetchInfoStep
import com.aliucord.manager.patcher.steps.prepare.*
import com.aliucord.manager.ui.screens.patchopts.PatchOptions
import kotlinx.collections.immutable.persistentListOf
@ -16,6 +15,7 @@ class KotlinPatchRunner(options: PatchOptions) : StepRunner() {
// Prepare
FetchInfoStep(),
DowngradeCheckStep(options),
RestoreDownloadsStep(),
// Download
DownloadDiscordStep(),

View file

@ -6,7 +6,6 @@ import com.aliucord.manager.manager.PreferencesManager
import com.aliucord.manager.patcher.StepRunner
import com.aliucord.manager.patcher.steps.StepGroup
import com.aliucord.manager.patcher.steps.base.Step
import com.aliucord.manager.patcher.steps.base.StepState
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
@ -21,9 +20,11 @@ class CleanupStep : Step(), KoinComponent {
override val localizedName = R.string.patch_step_cleanup
override suspend fun execute(container: StepRunner) {
container.log("Moving downloads back to cache")
paths.patchingDownloadDir.renameTo(paths.cacheDownloadDir)
if (prefs.keepPatchedApks) {
container.log("keepPatchedApks enabled, skipping...")
state = StepState.Skipped
container.log("keepPatchedApks enabled, keeping working dir")
} else {
container.log("Deleting patching working dir")
if (!paths.patchingWorkingDir().deleteRecursively())

View file

@ -0,0 +1,35 @@
package com.aliucord.manager.patcher.steps.prepare
import androidx.compose.runtime.Stable
import com.aliucord.manager.R
import com.aliucord.manager.manager.PathManager
import com.aliucord.manager.patcher.StepRunner
import com.aliucord.manager.patcher.steps.StepGroup
import com.aliucord.manager.patcher.steps.base.Step
import com.aliucord.manager.patcher.steps.base.StepState
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
/**
* Restores downloaded files necessary for patching from the cache dir.
* Refer to [PathManager.patchingDownloadDir] and [PathManager.cacheDownloadDir]
* for more information.
*/
@Stable
class RestoreDownloadsStep : Step(), KoinComponent {
private val paths: PathManager by inject()
override val group = StepGroup.Prepare
override val localizedName = R.string.patch_step_restore_cache
override suspend fun execute(container: StepRunner) {
if (paths.cacheDownloadDir.exists()) {
container.log("Moving downloads from cache to permanent storage")
paths.patchingDownloadDir.deleteRecursively()
paths.cacheDownloadDir.renameTo(paths.patchingDownloadDir)
} else {
container.log("No download cache present")
state = StepState.Skipped
}
}
}

View file

@ -119,6 +119,7 @@
<string name="patch_step_fetch_kt_version">Fetching target Discord version</string>
<string name="patch_step_downgrade_check">Checking for newer installations</string>
<string name="patch_step_restore_cache">Restoring from cache</string>
<string name="patch_step_dl_kt_apk">Downloading Discord APK</string>
<string name="patch_step_dl_kotlin">Downloading Kotlin library</string>
<string name="patch_step_dl_injector">Downloading Aliucord Injector</string>