mirror of
https://github.com/revanced/revanced-manager
synced 2024-05-14 13:56:57 +02:00
fix: delete temporary files (#1341)
This commit is contained in:
parent
abf4d91703
commit
723f9cd98c
@ -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
|
@ -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)
|
||||||
|
@ -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()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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,
|
||||||
|
@ -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
|
||||||
|
@ -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()
|
||||||
|
@ -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
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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) {
|
||||||
|
@ -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 {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user