From 94eac94ce76d85330c40e732380e2192f279e537 Mon Sep 17 00:00:00 2001 From: Cuong-Tran <16017808+cuong-tran@users.noreply.github.com> Date: Tue, 19 May 2026 15:44:58 +0700 Subject: [PATCH] ExtensionInstaller: Fix mistakenly canceling unrelated `waitingInstall` & avoid adding duplicate entry to installing `queue` (#1649) * ExtensionInstaller: Fix mistakenly canceling unrelated `waitingInstall` & avoid adding duplicate entry to installing `queue` - Changes the installer queue from a synchronized list to a synchronized set to prevent duplicate entries. - Updates queue removal logic to remove specific entries instead of using index-based removal. - Refines `cancelQueue` logic to ensure the active installation is only cancelled if its download ID matches the requested ID. * Ensure thread-safe access to the installation queue when canceling downloads --- .../tachiyomi/extension/installer/Installer.kt | 14 +++++++++++--- .../installer/PackageInstallerInstaller.kt | 7 +++---- .../extension/util/ExtensionInstallService.kt | 5 ++--- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/extension/installer/Installer.kt b/app/src/main/java/eu/kanade/tachiyomi/extension/installer/Installer.kt index 3a2200632..645a37d42 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/extension/installer/Installer.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/extension/installer/Installer.kt @@ -24,7 +24,9 @@ abstract class Installer(private val service: Service) { private val extensionManager: ExtensionManager by injectLazy() private var waitingInstall = AtomicReference(null) - private val queue = Collections.synchronizedList(mutableListOf()) + // KMK --> + private val queue = Collections.synchronizedSet(mutableSetOf()) + // KMK <-- private val cancelReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { @@ -104,7 +106,9 @@ abstract class Installer(private val service: Service) { } val nextEntry = queue.first() if (waitingInstall.compareAndSet(null, nextEntry)) { - queue.removeAt(0) + // KMK --> + queue.remove(nextEntry) + // KMK <-- processEntry(nextEntry) } } @@ -129,7 +133,11 @@ abstract class Installer(private val service: Service) { */ private fun cancelQueue(downloadId: Long) { val waitingInstall = this.waitingInstall.load() - val toCancel = queue.find { it.downloadId == downloadId } ?: waitingInstall ?: return + // KMK --> + val toCancel = synchronized(queue) { queue.find { it.downloadId == downloadId } } + ?: waitingInstall?.takeIf { it.downloadId == downloadId } + // KMK <-- + ?: return if (cancelEntry(toCancel)) { queue.remove(toCancel) if (waitingInstall == toCancel) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/extension/installer/PackageInstallerInstaller.kt b/app/src/main/java/eu/kanade/tachiyomi/extension/installer/PackageInstallerInstaller.kt index e65862330..a3e37a6aa 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/extension/installer/PackageInstallerInstaller.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/extension/installer/PackageInstallerInstaller.kt @@ -15,8 +15,7 @@ import eu.kanade.tachiyomi.extension.model.InstallStep import eu.kanade.tachiyomi.util.lang.use import eu.kanade.tachiyomi.util.system.getParcelableExtraCompat import eu.kanade.tachiyomi.util.system.getUriSize -import logcat.LogPriority -import tachiyomi.core.common.util.system.logcat +import exh.log.xLogE class PackageInstallerInstaller(private val service: Service) : Installer(service) { @@ -42,7 +41,7 @@ class PackageInstallerInstaller(private val service: Service) : Installer(servic .sanitizeByFiltering(this) } if (userAction == null) { - logcat(LogPriority.ERROR) { "Fatal error for $intent" } + xLogE("Fatal error for $intent") continueQueue(InstallStep.Error) return } @@ -95,7 +94,7 @@ class PackageInstallerInstaller(private val service: Service) : Installer(servic session.commit(intentSender) } } catch (e: Exception) { - logcat(LogPriority.ERROR, e) { "Failed to install extension ${entry.downloadId} ${entry.uri}" } + xLogE("Failed to install extension ${entry.downloadId} ${entry.uri}", e) activeSession?.let { (_, sessionId) -> packageInstaller.abandonSession(sessionId) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionInstallService.kt b/app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionInstallService.kt index dab5df61e..f082fe4a1 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionInstallService.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionInstallService.kt @@ -16,9 +16,8 @@ import eu.kanade.tachiyomi.extension.installer.ShizukuInstaller import eu.kanade.tachiyomi.extension.util.ExtensionInstaller.Companion.EXTRA_DOWNLOAD_ID import eu.kanade.tachiyomi.util.system.getSerializableExtraCompat import eu.kanade.tachiyomi.util.system.notificationBuilder -import logcat.LogPriority +import exh.log.xLogE import tachiyomi.core.common.i18n.stringResource -import tachiyomi.core.common.util.system.logcat import tachiyomi.i18n.MR class ExtensionInstallService : Service() { @@ -53,7 +52,7 @@ class ExtensionInstallService : Service() { BasePreferences.ExtensionInstaller.PACKAGEINSTALLER -> PackageInstallerInstaller(this) BasePreferences.ExtensionInstaller.SHIZUKU -> ShizukuInstaller(this) else -> { - logcat(LogPriority.ERROR) { "Not implemented for installer $installerUsed" } + xLogE("Not implemented for installer $installerUsed") stopSelf() return START_NOT_STICKY }