diff --git a/app/src/main/java/com/aurora/store/data/helper/DownloadHelper.kt b/app/src/main/java/com/aurora/store/data/helper/DownloadHelper.kt index 663d640e4..44f8ade6e 100644 --- a/app/src/main/java/com/aurora/store/data/helper/DownloadHelper.kt +++ b/app/src/main/java/com/aurora/store/data/helper/DownloadHelper.kt @@ -162,6 +162,8 @@ class DownloadHelper @Inject constructor( suspend fun cancelDownload(packageName: String) { Log.i(TAG, "Cancelling download for $packageName") WorkManager.getInstance(context).cancelAllWorkByTag("$PACKAGE_NAME:$packageName") + // Abandon any session already staged for install so we don't leak it. + runCatching { appInstaller.getPreferredInstaller().cancelInstall(packageName) } downloadDao.updateStatus(packageName, DownloadStatus.CANCELLED) } diff --git a/app/src/main/java/com/aurora/store/data/installer/SessionInstaller.kt b/app/src/main/java/com/aurora/store/data/installer/SessionInstaller.kt index f3726d7f4..413ca79e0 100644 --- a/app/src/main/java/com/aurora/store/data/installer/SessionInstaller.kt +++ b/app/src/main/java/com/aurora/store/data/installer/SessionInstaller.kt @@ -182,6 +182,16 @@ class SessionInstaller @Inject constructor( } } + override fun cancelInstall(packageName: String) { + val sessionSet = enqueuedSessions + .find { set -> set.any { it.packageName == packageName } } ?: return + + Log.i(TAG, "Abandoning staged session(s) for $packageName") + sessionSet.forEach { runCatching { packageInstaller.abandonSession(it.sessionId) } } + enqueuedSessions.remove(sessionSet) + removeFromInstallQueue(packageName) + } + private fun stageInstall( packageName: String, versionCode: Long, diff --git a/app/src/main/java/com/aurora/store/data/installer/base/IInstaller.kt b/app/src/main/java/com/aurora/store/data/installer/base/IInstaller.kt index 2c832110f..10b02f4a6 100644 --- a/app/src/main/java/com/aurora/store/data/installer/base/IInstaller.kt +++ b/app/src/main/java/com/aurora/store/data/installer/base/IInstaller.kt @@ -26,4 +26,11 @@ interface IInstaller { fun clearQueue() fun isAlreadyQueued(packageName: String): Boolean fun removeFromInstallQueue(packageName: String) + + /** + * Abandons any staged-but-uncommitted install session for [packageName] so cancelling + * a download doesn't leak a [android.content.pm.PackageInstaller] session. Default no-op + * for installers that don't stage sessions. + */ + fun cancelInstall(packageName: String) {} }