From eedf6abf91fd763fc5d1fea66aef1bfefcc0a2b6 Mon Sep 17 00:00:00 2001 From: Nik Clayton Date: Mon, 12 Jun 2023 22:04:58 +0200 Subject: [PATCH] Catch missing classes in WorkerFactory (#3744) When NotificationWorker was moved from ...components.notifications to ...worker. Installing Tusky with this change doesn't remove any future periodic jobs queued under the old class name. So when Class.forName() is called the old class name is not found, and the exception is thrown. Handle this the same way androidx.work.WorkerFactory does -- catch the exception, log it, and return null. Fixes #3740 --- .../tusky/worker/WorkerFactory.kt | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/keylesspalace/tusky/worker/WorkerFactory.kt b/app/src/main/java/com/keylesspalace/tusky/worker/WorkerFactory.kt index 73c87b2e..1d44b2ea 100644 --- a/app/src/main/java/com/keylesspalace/tusky/worker/WorkerFactory.kt +++ b/app/src/main/java/com/keylesspalace/tusky/worker/WorkerFactory.kt @@ -18,11 +18,13 @@ package com.keylesspalace.tusky.worker import android.content.Context +import android.util.Log import androidx.work.ListenableWorker import androidx.work.WorkerFactory import androidx.work.WorkerParameters import javax.inject.Inject import javax.inject.Provider +import javax.inject.Singleton /** * Workers implement this and are added to the map in [com.keylesspalace.tusky.di.WorkerModule] @@ -37,20 +39,33 @@ interface ChildWorkerFactory { * Creates workers, delegating to each worker's [ChildWorkerFactory.createWorker] to do the * creation. * - * @see [com.keylesspalace.tusky.components.notifications.NotificationWorker] + * @see [com.keylesspalace.tusky.worker.NotificationWorker] */ +@Singleton class WorkerFactory @Inject constructor( - val workerFactories: Map, @JvmSuppressWildcards Provider> + private val workerFactories: Map, @JvmSuppressWildcards Provider> ) : WorkerFactory() { override fun createWorker( appContext: Context, workerClassName: String, workerParameters: WorkerParameters ): ListenableWorker? { - val key = Class.forName(workerClassName) + val key = try { + Class.forName(workerClassName) + } catch (e: ClassNotFoundException) { + // Class might be missing if it was renamed / moved to a different package, as + // periodic work requests from before the rename might still exist. Catch and + // return null, which should stop future requests. + Log.d(TAG, "Invalid class: $workerClassName", e) + null + } workerFactories[key]?.let { return it.get().createWorker(appContext, workerParameters) } return null } + + companion object { + private const val TAG = "WorkerFactory" + } }