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
This commit is contained in:
Nik Clayton 2023-06-12 22:04:58 +02:00 committed by GitHub
parent 5327c9f572
commit eedf6abf91
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -18,11 +18,13 @@
package com.keylesspalace.tusky.worker package com.keylesspalace.tusky.worker
import android.content.Context import android.content.Context
import android.util.Log
import androidx.work.ListenableWorker import androidx.work.ListenableWorker
import androidx.work.WorkerFactory import androidx.work.WorkerFactory
import androidx.work.WorkerParameters import androidx.work.WorkerParameters
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Provider import javax.inject.Provider
import javax.inject.Singleton
/** /**
* Workers implement this and are added to the map in [com.keylesspalace.tusky.di.WorkerModule] * 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 * Creates workers, delegating to each worker's [ChildWorkerFactory.createWorker] to do the
* creation. * creation.
* *
* @see [com.keylesspalace.tusky.components.notifications.NotificationWorker] * @see [com.keylesspalace.tusky.worker.NotificationWorker]
*/ */
@Singleton
class WorkerFactory @Inject constructor( class WorkerFactory @Inject constructor(
val workerFactories: Map<Class<out ListenableWorker>, @JvmSuppressWildcards Provider<ChildWorkerFactory>> private val workerFactories: Map<Class<out ListenableWorker>, @JvmSuppressWildcards Provider<ChildWorkerFactory>>
) : WorkerFactory() { ) : WorkerFactory() {
override fun createWorker( override fun createWorker(
appContext: Context, appContext: Context,
workerClassName: String, workerClassName: String,
workerParameters: WorkerParameters workerParameters: WorkerParameters
): ListenableWorker? { ): 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 { workerFactories[key]?.let {
return it.get().createWorker(appContext, workerParameters) return it.get().createWorker(appContext, workerParameters)
} }
return null return null
} }
companion object {
private const val TAG = "WorkerFactory"
}
} }