fix: delete temporary files (#1341)

This commit is contained in:
Ax333l 2023-10-07 16:09:02 +02:00 committed by GitHub
parent abf4d91703
commit 723f9cd98c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 66 additions and 33 deletions

View File

@ -9,9 +9,18 @@ import androidx.activity.result.contract.ActivityResultContract
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import app.revanced.manager.util.RequestManageStorageContract import app.revanced.manager.util.RequestManageStorageContract
class FileSystem(private val app: Application) { class Filesystem(private val app: Application) {
val contentResolver = app.contentResolver // TODO: move Content Resolver operations to here. val contentResolver = app.contentResolver // TODO: move Content Resolver operations to here.
/**
* A directory that gets cleared when the app restarts.
* Do not store paths to this directory in a parcel.
*/
val tempDir = app.cacheDir.resolve("ephemeral").apply {
deleteRecursively()
mkdirs()
}
fun externalFilesDir() = Environment.getExternalStorageDirectory().toPath() fun externalFilesDir() = Environment.getExternalStorageDirectory().toPath()
private fun usesManagePermission() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.R private fun usesManagePermission() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.R

View File

@ -1,17 +1,20 @@
package app.revanced.manager.di package app.revanced.manager.di
import app.revanced.manager.data.platform.FileSystem import app.revanced.manager.data.platform.Filesystem
import app.revanced.manager.data.platform.NetworkInfo import app.revanced.manager.data.platform.NetworkInfo
import app.revanced.manager.domain.repository.* import app.revanced.manager.domain.repository.*
import app.revanced.manager.domain.worker.WorkerRepository import app.revanced.manager.domain.worker.WorkerRepository
import app.revanced.manager.network.api.ReVancedAPI import app.revanced.manager.network.api.ReVancedAPI
import org.koin.core.module.dsl.createdAtStart
import org.koin.core.module.dsl.singleOf import org.koin.core.module.dsl.singleOf
import org.koin.dsl.module import org.koin.dsl.module
val repositoryModule = module { val repositoryModule = module {
singleOf(::ReVancedAPI) singleOf(::ReVancedAPI)
singleOf(::GithubRepository) singleOf(::GithubRepository)
singleOf(::FileSystem) singleOf(::Filesystem) {
createdAtStart()
}
singleOf(::NetworkInfo) singleOf(::NetworkInfo)
singleOf(::PatchBundlePersistenceRepository) singleOf(::PatchBundlePersistenceRepository)
singleOf(::PatchSelectionRepository) singleOf(::PatchSelectionRepository)

View File

@ -24,16 +24,17 @@ class Session(
private val input: File, private val input: File,
private val onStepSucceeded: suspend () -> Unit private val onStepSucceeded: suspend () -> Unit
) : Closeable { ) : Closeable {
private val temporary = File(cacheDir).resolve("manager").also { it.mkdirs() } private val tempDir = File(cacheDir).resolve("patcher").also { it.mkdirs() }
private val patcher = Patcher( private val patcher = Patcher(
PatcherOptions( PatcherOptions(
inputFile = input, inputFile = input,
resourceCachePath = temporary.resolve("aapt-resources"), resourceCachePath = tempDir.resolve("aapt-resources"),
frameworkFileDirectory = frameworkDir, frameworkFileDirectory = frameworkDir,
aaptBinaryPath = aaptPath aaptBinaryPath = aaptPath
) )
) )
private suspend fun Patcher.applyPatchesVerbose() { private suspend fun Patcher.applyPatchesVerbose() {
this.apply(true).collect { (patch, exception) -> this.apply(true).collect { (patch, exception) ->
if (exception == null) { if (exception == null) {
@ -70,7 +71,7 @@ class Session(
logger.info("Writing patched files...") logger.info("Writing patched files...")
val result = patcher.get() val result = patcher.get()
val aligned = temporary.resolve("aligned.apk") val aligned = tempDir.resolve("aligned.apk")
ApkUtils.copyAligned(input, aligned, result) ApkUtils.copyAligned(input, aligned, result)
logger.info("Patched apk saved to $aligned") logger.info("Patched apk saved to $aligned")
@ -82,7 +83,7 @@ class Session(
} }
override fun close() { override fun close() {
temporary.delete() tempDir.deleteRecursively()
patcher.close() patcher.close()
} }

View File

@ -14,6 +14,7 @@ import androidx.core.content.ContextCompat
import androidx.work.ForegroundInfo import androidx.work.ForegroundInfo
import androidx.work.WorkerParameters import androidx.work.WorkerParameters
import app.revanced.manager.R import app.revanced.manager.R
import app.revanced.manager.data.platform.Filesystem
import app.revanced.manager.data.room.apps.installed.InstallType import app.revanced.manager.data.room.apps.installed.InstallType
import app.revanced.manager.domain.installer.RootInstaller import app.revanced.manager.domain.installer.RootInstaller
import app.revanced.manager.domain.manager.PreferencesManager import app.revanced.manager.domain.manager.PreferencesManager
@ -49,6 +50,7 @@ class PatcherWorker(
private val prefs: PreferencesManager by inject() private val prefs: PreferencesManager by inject()
private val downloadedAppRepository: DownloadedAppRepository by inject() private val downloadedAppRepository: DownloadedAppRepository by inject()
private val pm: PM by inject() private val pm: PM by inject()
private val fs: Filesystem by inject()
private val installedAppRepository: InstalledAppRepository by inject() private val installedAppRepository: InstalledAppRepository by inject()
private val rootInstaller: RootInstaller by inject() private val rootInstaller: RootInstaller by inject()
@ -57,13 +59,12 @@ class PatcherWorker(
val output: String, val output: String,
val selectedPatches: PatchesSelection, val selectedPatches: PatchesSelection,
val options: Options, val options: Options,
val packageName: String,
val packageVersion: String,
val progress: MutableStateFlow<ImmutableList<Step>>, val progress: MutableStateFlow<ImmutableList<Step>>,
val logger: ManagerLogger, val logger: ManagerLogger,
val selectedApp: SelectedApp,
val setInputFile: (File) -> Unit val setInputFile: (File) -> Unit
) ) {
val packageName get() = input.packageName
}
companion object { companion object {
private const val logPrefix = "[Worker]:" private const val logPrefix = "[Worker]:"
@ -153,7 +154,7 @@ class PatcherWorker(
return try { return try {
if (args.selectedApp is SelectedApp.Installed) { if (args.input is SelectedApp.Installed) {
installedAppRepository.get(args.packageName)?.let { installedAppRepository.get(args.packageName)?.let {
if (it.installType == InstallType.ROOT) { if (it.installType == InstallType.ROOT) {
rootInstaller.unmount(args.packageName) rootInstaller.unmount(args.packageName)
@ -212,7 +213,7 @@ class PatcherWorker(
} }
Session( Session(
applicationContext.cacheDir.absolutePath, fs.tempDir.absolutePath,
frameworkPath, frameworkPath,
aaptPath, aaptPath,
args.logger, args.logger,

View File

@ -26,7 +26,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import app.revanced.manager.R import app.revanced.manager.R
import app.revanced.manager.data.platform.FileSystem import app.revanced.manager.data.platform.Filesystem
import app.revanced.manager.patcher.patch.Option import app.revanced.manager.patcher.patch.Option
import app.revanced.manager.util.toast import app.revanced.manager.util.toast
import app.revanced.patcher.patch.options.types.* import app.revanced.patcher.patch.options.types.*
@ -61,7 +61,7 @@ private fun StringOptionDialog(
mutableStateOf(value.orEmpty()) mutableStateOf(value.orEmpty())
} }
val fs: FileSystem = rememberKoinInject() val fs: Filesystem = rememberKoinInject()
val (contract, permissionName) = fs.permissionContract() val (contract, permissionName) = fs.permissionContract()
val permissionLauncher = rememberLauncherForActivityResult(contract = contract) { val permissionLauncher = rememberLauncherForActivityResult(contract = contract) {
showFileDialog = it showFileDialog = it

View File

@ -13,7 +13,7 @@ sealed class SelectedApp : Parcelable {
data class Download(override val packageName: String, override val version: String, val app: AppDownloader.App) : SelectedApp() data class Download(override val packageName: String, override val version: String, val app: AppDownloader.App) : SelectedApp()
@Parcelize @Parcelize
data class Local(override val packageName: String, override val version: String, val file: File) : SelectedApp() data class Local(override val packageName: String, override val version: String, val file: File, val shouldDelete: Boolean) : SelectedApp()
@Parcelize @Parcelize
data class Installed(override val packageName: String, override val version: String) : SelectedApp() data class Installed(override val packageName: String, override val version: String) : SelectedApp()

View File

@ -13,19 +13,26 @@ class AppSelectorViewModel(
private val app: Application, private val app: Application,
private val pm: PM private val pm: PM
) : ViewModel() { ) : ViewModel() {
private val inputFile = File(app.cacheDir, "input.apk").also {
it.delete()
}
val appList = pm.appList val appList = pm.appList
fun loadLabel(app: PackageInfo?) = with(pm) { app?.label() ?: "Not installed" } fun loadLabel(app: PackageInfo?) = with(pm) { app?.label() ?: "Not installed" }
fun loadSelectedFile(uri: Uri) = fun loadSelectedFile(uri: Uri) =
app.contentResolver.openInputStream(uri)?.use { stream -> app.contentResolver.openInputStream(uri)?.use { stream ->
File(app.cacheDir, "input.apk").also { with(inputFile) {
it.delete() delete()
Files.copy(stream, it.toPath()) Files.copy(stream, toPath())
}.let { file ->
pm.getPackageInfo(file) pm.getPackageInfo(this)?.let { packageInfo ->
?.let { packageInfo -> SelectedApp.Local(
SelectedApp.Local(packageName = packageInfo.packageName, version = packageInfo.versionName, file = file) packageName = packageInfo.packageName,
version = packageInfo.versionName,
file = this,
shouldDelete = true
)
} }
} }
} }

View File

@ -19,6 +19,7 @@ import androidx.lifecycle.viewModelScope
import androidx.work.WorkInfo import androidx.work.WorkInfo
import androidx.work.WorkManager import androidx.work.WorkManager
import app.revanced.manager.R import app.revanced.manager.R
import app.revanced.manager.data.platform.Filesystem
import app.revanced.manager.data.room.apps.installed.InstallType import app.revanced.manager.data.room.apps.installed.InstallType
import app.revanced.manager.data.room.apps.installed.InstalledApp import app.revanced.manager.data.room.apps.installed.InstalledApp
import app.revanced.manager.domain.installer.RootInstaller import app.revanced.manager.domain.installer.RootInstaller
@ -57,16 +58,22 @@ class InstallerViewModel(
) : ViewModel(), KoinComponent { ) : ViewModel(), KoinComponent {
private val keystoreManager: KeystoreManager by inject() private val keystoreManager: KeystoreManager by inject()
private val app: Application by inject() private val app: Application by inject()
private val fs: Filesystem by inject()
private val pm: PM by inject() private val pm: PM by inject()
private val workerRepository: WorkerRepository by inject() private val workerRepository: WorkerRepository by inject()
private val installedAppRepository: InstalledAppRepository by inject() private val installedAppRepository: InstalledAppRepository by inject()
private val rootInstaller: RootInstaller by inject() private val rootInstaller: RootInstaller by inject()
val packageName: String = input.selectedApp.packageName val packageName: String = input.selectedApp.packageName
private val outputFile = File(app.cacheDir, "output.apk") private val tempDir = fs.tempDir.resolve("installer").also {
private val signedFile = File(app.cacheDir, "signed.apk").also { if (it.exists()) it.delete() } it.deleteRecursively()
it.mkdirs()
}
private val outputFile = tempDir.resolve("output.apk")
private val signedFile = tempDir.resolve("signed.apk")
private var hasSigned = false private var hasSigned = false
var inputFile: File? = null private var inputFile: File? = null
private var installedApp: InstalledApp? = null private var installedApp: InstalledApp? = null
var isInstalling by mutableStateOf(false) var isInstalling by mutableStateOf(false)
@ -82,6 +89,8 @@ class InstallerViewModel(
private val logger = ManagerLogger() private val logger = ManagerLogger()
init { init {
// TODO: navigate away when system-initiated process death is detected because it is not possible to recover from it.
viewModelScope.launch { viewModelScope.launch {
installedApp = installedAppRepository.get(packageName) installedApp = installedAppRepository.get(packageName)
} }
@ -101,11 +110,8 @@ class InstallerViewModel(
outputFile.path, outputFile.path,
patches, patches,
options, options,
packageName,
selectedApp.version,
_progress, _progress,
logger, logger,
selectedApp,
setInputFile = { inputFile = it } setInputFile = { inputFile = it }
) )
) )
@ -176,8 +182,14 @@ class InstallerViewModel(
app.unregisterReceiver(installBroadcastReceiver) app.unregisterReceiver(installBroadcastReceiver)
workManager.cancelWorkById(patcherWorkerId) workManager.cancelWorkById(patcherWorkerId)
outputFile.delete() when (val selectedApp = input.selectedApp) {
signedFile.delete() is SelectedApp.Local -> {
if (selectedApp.shouldDelete) selectedApp.file.delete()
}
else -> {}
}
tempDir.deleteRecursively()
try { try {
if (input.selectedApp is SelectedApp.Installed) { if (input.selectedApp is SelectedApp.Installed) {

View File

@ -68,7 +68,7 @@ class VersionSelectorViewModel(
} }
val downloadedVersions = downloadedAppRepository.getAll().map { downloadedApps -> val downloadedVersions = downloadedAppRepository.getAll().map { downloadedApps ->
downloadedApps.filter { it.packageName == packageName }.map { SelectedApp.Local(it.packageName, it.version, it.file) } downloadedApps.filter { it.packageName == packageName }.map { SelectedApp.Local(it.packageName, it.version, it.file, false) }
} }
init { init {