From c98926a40ca1f023d6ef97accd7f2341c67eace7 Mon Sep 17 00:00:00 2001 From: Cris Barreiro Date: Mon, 24 Feb 2025 14:57:33 +0100 Subject: [PATCH 1/2] Add killswitch for update, and force update when downloading privacy config --- .../impl/MaliciousSiteProtectionFeature.kt | 7 +++++++ ...iciousSiteProtectionFiltersUpdateWorker.kt | 17 ++++++++++------- ...sSiteProtectionHashPrefixesUpdateWorker.kt | 13 ++++++------- .../impl/MaliciousSiteProtectionRCFeature.kt | 10 +++++++++- ...usSiteProtectionFiltersUpdateWorkerTest.kt | 19 ++++++++++++++++--- ...eProtectionHashPrefixesUpdateWorkerTest.kt | 19 ++++++++++++++++--- 6 files changed, 64 insertions(+), 21 deletions(-) diff --git a/malicious-site-protection/malicious-site-protection-impl/src/main/kotlin/com/duckduckgo/malicioussiteprotection/impl/MaliciousSiteProtectionFeature.kt b/malicious-site-protection/malicious-site-protection-impl/src/main/kotlin/com/duckduckgo/malicioussiteprotection/impl/MaliciousSiteProtectionFeature.kt index bf3b6892c6cf..161ceef47f8c 100644 --- a/malicious-site-protection/malicious-site-protection-impl/src/main/kotlin/com/duckduckgo/malicioussiteprotection/impl/MaliciousSiteProtectionFeature.kt +++ b/malicious-site-protection/malicious-site-protection-impl/src/main/kotlin/com/duckduckgo/malicioussiteprotection/impl/MaliciousSiteProtectionFeature.kt @@ -35,4 +35,11 @@ interface MaliciousSiteProtectionFeature { @Toggle.InternalAlwaysEnabled @Toggle.DefaultValue(false) fun self(): Toggle + + @Toggle.InternalAlwaysEnabled + @Toggle.DefaultValue(false) + fun visibleAndOnByDefault(): Toggle + + @Toggle.DefaultValue(true) + fun canUpdateDatasets(): Toggle } diff --git a/malicious-site-protection/malicious-site-protection-impl/src/main/kotlin/com/duckduckgo/malicioussiteprotection/impl/MaliciousSiteProtectionFiltersUpdateWorker.kt b/malicious-site-protection/malicious-site-protection-impl/src/main/kotlin/com/duckduckgo/malicioussiteprotection/impl/MaliciousSiteProtectionFiltersUpdateWorker.kt index 0971c00c7827..7367112b25b9 100644 --- a/malicious-site-protection/malicious-site-protection-impl/src/main/kotlin/com/duckduckgo/malicioussiteprotection/impl/MaliciousSiteProtectionFiltersUpdateWorker.kt +++ b/malicious-site-protection/malicious-site-protection-impl/src/main/kotlin/com/duckduckgo/malicioussiteprotection/impl/MaliciousSiteProtectionFiltersUpdateWorker.kt @@ -17,7 +17,6 @@ package com.duckduckgo.malicioussiteprotection.impl import android.content.Context -import androidx.lifecycle.LifecycleOwner import androidx.work.BackoffPolicy import androidx.work.CoroutineWorker import androidx.work.ExistingPeriodicWorkPolicy @@ -25,10 +24,10 @@ import androidx.work.PeriodicWorkRequestBuilder import androidx.work.WorkManager import androidx.work.WorkerParameters import com.duckduckgo.anvil.annotations.ContributesWorker -import com.duckduckgo.app.lifecycle.MainProcessLifecycleObserver import com.duckduckgo.common.utils.DispatcherProvider import com.duckduckgo.di.scopes.AppScope import com.duckduckgo.malicioussiteprotection.impl.data.MaliciousSiteRepository +import com.duckduckgo.privacy.config.api.PrivacyConfigCallbackPlugin import com.squareup.anvil.annotations.ContributesMultibinding import dagger.SingleInstanceIn import java.util.concurrent.TimeUnit @@ -51,7 +50,7 @@ class MaliciousSiteProtectionFiltersUpdateWorker( override suspend fun doWork(): Result { return withContext(dispatcherProvider.io()) { - if (maliciousSiteProtectionFeature.isFeatureEnabled().not()) { + if (maliciousSiteProtectionFeature.isFeatureEnabled().not() || maliciousSiteProtectionFeature.canUpdateDatasets().not()) { return@withContext Result.success() } return@withContext if (maliciousSiteRepository.loadFilters().isSuccess) { @@ -65,16 +64,16 @@ class MaliciousSiteProtectionFiltersUpdateWorker( @ContributesMultibinding( scope = AppScope::class, - boundType = MainProcessLifecycleObserver::class, + boundType = PrivacyConfigCallbackPlugin::class, ) @SingleInstanceIn(AppScope::class) class MaliciousSiteProtectionFiltersUpdateWorkerScheduler @Inject constructor( private val workManager: WorkManager, private val maliciousSiteProtectionFeature: MaliciousSiteProtectionRCFeature, -) : MainProcessLifecycleObserver { +) : PrivacyConfigCallbackPlugin { - override fun onCreate(owner: LifecycleOwner) { + override fun onPrivacyConfigDownloaded() { val workerRequest = PeriodicWorkRequestBuilder( maliciousSiteProtectionFeature.getFilterSetUpdateFrequency(), TimeUnit.MINUTES, @@ -82,7 +81,11 @@ class MaliciousSiteProtectionFiltersUpdateWorkerScheduler @Inject constructor( .addTag(MALICIOUS_SITE_PROTECTION_FILTERS_UPDATE_WORKER_TAG) .setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 1, TimeUnit.MINUTES) .build() - workManager.enqueueUniquePeriodicWork(MALICIOUS_SITE_PROTECTION_FILTERS_UPDATE_WORKER_TAG, ExistingPeriodicWorkPolicy.UPDATE, workerRequest) + workManager.enqueueUniquePeriodicWork( + MALICIOUS_SITE_PROTECTION_FILTERS_UPDATE_WORKER_TAG, + ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE, + workerRequest, + ) } companion object { diff --git a/malicious-site-protection/malicious-site-protection-impl/src/main/kotlin/com/duckduckgo/malicioussiteprotection/impl/MaliciousSiteProtectionHashPrefixesUpdateWorker.kt b/malicious-site-protection/malicious-site-protection-impl/src/main/kotlin/com/duckduckgo/malicioussiteprotection/impl/MaliciousSiteProtectionHashPrefixesUpdateWorker.kt index fe111bcb225a..cf1602983362 100644 --- a/malicious-site-protection/malicious-site-protection-impl/src/main/kotlin/com/duckduckgo/malicioussiteprotection/impl/MaliciousSiteProtectionHashPrefixesUpdateWorker.kt +++ b/malicious-site-protection/malicious-site-protection-impl/src/main/kotlin/com/duckduckgo/malicioussiteprotection/impl/MaliciousSiteProtectionHashPrefixesUpdateWorker.kt @@ -17,7 +17,6 @@ package com.duckduckgo.malicioussiteprotection.impl import android.content.Context -import androidx.lifecycle.LifecycleOwner import androidx.work.BackoffPolicy import androidx.work.CoroutineWorker import androidx.work.ExistingPeriodicWorkPolicy @@ -25,10 +24,10 @@ import androidx.work.PeriodicWorkRequestBuilder import androidx.work.WorkManager import androidx.work.WorkerParameters import com.duckduckgo.anvil.annotations.ContributesWorker -import com.duckduckgo.app.lifecycle.MainProcessLifecycleObserver import com.duckduckgo.common.utils.DispatcherProvider import com.duckduckgo.di.scopes.AppScope import com.duckduckgo.malicioussiteprotection.impl.data.MaliciousSiteRepository +import com.duckduckgo.privacy.config.api.PrivacyConfigCallbackPlugin import com.squareup.anvil.annotations.ContributesMultibinding import dagger.SingleInstanceIn import java.util.concurrent.TimeUnit @@ -51,7 +50,7 @@ class MaliciousSiteProtectionHashPrefixesUpdateWorker( override suspend fun doWork(): Result { return withContext(dispatcherProvider.io()) { - if (maliciousSiteProtectionFeature.isFeatureEnabled().not()) { + if (maliciousSiteProtectionFeature.isFeatureEnabled().not() || maliciousSiteProtectionFeature.canUpdateDatasets().not()) { return@withContext Result.success() } return@withContext if (maliciousSiteRepository.loadHashPrefixes().isSuccess) { @@ -65,16 +64,16 @@ class MaliciousSiteProtectionHashPrefixesUpdateWorker( @ContributesMultibinding( scope = AppScope::class, - boundType = MainProcessLifecycleObserver::class, + boundType = PrivacyConfigCallbackPlugin::class, ) @SingleInstanceIn(AppScope::class) class MaliciousSiteProtectionHashPrefixesUpdateWorkerScheduler @Inject constructor( private val workManager: WorkManager, private val maliciousSiteProtectionFeature: MaliciousSiteProtectionRCFeature, -) : MainProcessLifecycleObserver { +) : PrivacyConfigCallbackPlugin { - override fun onCreate(owner: LifecycleOwner) { + override fun onPrivacyConfigDownloaded() { val workerRequest = PeriodicWorkRequestBuilder( maliciousSiteProtectionFeature.getHashPrefixUpdateFrequency(), TimeUnit.MINUTES, @@ -84,7 +83,7 @@ class MaliciousSiteProtectionHashPrefixesUpdateWorkerScheduler @Inject construct .build() workManager.enqueueUniquePeriodicWork( MALICIOUS_SITE_PROTECTION_HASH_PREFIXES_UPDATE_WORKER_TAG, - ExistingPeriodicWorkPolicy.UPDATE, + ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE, workerRequest, ) } diff --git a/malicious-site-protection/malicious-site-protection-impl/src/main/kotlin/com/duckduckgo/malicioussiteprotection/impl/MaliciousSiteProtectionRCFeature.kt b/malicious-site-protection/malicious-site-protection-impl/src/main/kotlin/com/duckduckgo/malicioussiteprotection/impl/MaliciousSiteProtectionRCFeature.kt index 16db750c413d..97b7f5f954d8 100644 --- a/malicious-site-protection/malicious-site-protection-impl/src/main/kotlin/com/duckduckgo/malicioussiteprotection/impl/MaliciousSiteProtectionRCFeature.kt +++ b/malicious-site-protection/malicious-site-protection-impl/src/main/kotlin/com/duckduckgo/malicioussiteprotection/impl/MaliciousSiteProtectionRCFeature.kt @@ -31,6 +31,7 @@ import org.json.JSONObject interface MaliciousSiteProtectionRCFeature { fun isFeatureEnabled(): Boolean + fun canUpdateDatasets(): Boolean fun getHashPrefixUpdateFrequency(): Long fun getFilterSetUpdateFrequency(): Long } @@ -45,6 +46,7 @@ class RealMaliciousSiteProtectionRCFeature @Inject constructor( @AppCoroutineScope private val appCoroutineScope: CoroutineScope, ) : MaliciousSiteProtectionRCFeature, PrivacyConfigCallbackPlugin { private var isFeatureEnabled = false + private var canUpdateDatasets = false private var hashPrefixUpdateFrequency = 20L private var filterSetUpdateFrequency = 720L @@ -71,9 +73,15 @@ class RealMaliciousSiteProtectionRCFeature @Inject constructor( return isFeatureEnabled } + override fun canUpdateDatasets(): Boolean { + return canUpdateDatasets + } + private fun loadToMemory() { appCoroutineScope.launch(dispatchers.io()) { - isFeatureEnabled = maliciousSiteProtectionFeature.self().isEnabled() + isFeatureEnabled = maliciousSiteProtectionFeature.self().isEnabled() && + maliciousSiteProtectionFeature.visibleAndOnByDefault().isEnabled() + canUpdateDatasets = maliciousSiteProtectionFeature.canUpdateDatasets().isEnabled() maliciousSiteProtectionFeature.self().getSettings()?.let { JSONObject(it).let { settings -> hashPrefixUpdateFrequency = settings.getLong("hashPrefixUpdateFrequency") diff --git a/malicious-site-protection/malicious-site-protection-impl/src/test/kotlin/com/duckduckgo/malicioussiteprotection/impl/MaliciousSiteProtectionFiltersUpdateWorkerTest.kt b/malicious-site-protection/malicious-site-protection-impl/src/test/kotlin/com/duckduckgo/malicioussiteprotection/impl/MaliciousSiteProtectionFiltersUpdateWorkerTest.kt index 1e2c670c4484..3e0cc5e2785c 100644 --- a/malicious-site-protection/malicious-site-protection-impl/src/test/kotlin/com/duckduckgo/malicioussiteprotection/impl/MaliciousSiteProtectionFiltersUpdateWorkerTest.kt +++ b/malicious-site-protection/malicious-site-protection-impl/src/test/kotlin/com/duckduckgo/malicioussiteprotection/impl/MaliciousSiteProtectionFiltersUpdateWorkerTest.kt @@ -22,6 +22,7 @@ import org.mockito.Mockito.mock import org.mockito.Mockito.verify import org.mockito.kotlin.capture import org.mockito.kotlin.eq +import org.mockito.kotlin.never import org.mockito.kotlin.whenever @RunWith(AndroidJUnit4::class) @@ -41,6 +42,7 @@ class MaliciousSiteProtectionFiltersUpdateWorkerTest { worker.maliciousSiteRepository = maliciousSiteRepository worker.dispatcherProvider = dispatcherProvider worker.maliciousSiteProtectionFeature = maliciousSiteProtectionFeature + whenever(maliciousSiteProtectionFeature.canUpdateDatasets()).thenReturn(true) } @Test @@ -49,6 +51,17 @@ class MaliciousSiteProtectionFiltersUpdateWorkerTest { val result = worker.doWork() + verify(maliciousSiteRepository, never()).loadFilters() + assertEquals(success(), result) + } + + @Test + fun doWork_returnsSuccessWhenCanUpdateDatasetsIsDisabled() = runTest { + whenever(maliciousSiteProtectionFeature.canUpdateDatasets()).thenReturn(false) + + val result = worker.doWork() + + verify(maliciousSiteRepository, never()).loadFilters() assertEquals(success(), result) } @@ -80,17 +93,17 @@ class MaliciousSiteProtectionFiltersUpdateWorkerSchedulerTest { private val scheduler = MaliciousSiteProtectionFiltersUpdateWorkerScheduler(workManager, maliciousSiteProtectionFeature) @Test - fun onCreate_schedulesWorkerWithUpdateFrequencyFromRCFlag() { + fun onPrivacyConfigDownloaded_schedulesWorkerWithUpdateFrequencyFromRCFlagAndReenqueuePolicy() { val updateFrequencyMinutes = 15L whenever(maliciousSiteProtectionFeature.getFilterSetUpdateFrequency()).thenReturn(updateFrequencyMinutes) - scheduler.onCreate(mock()) + scheduler.onPrivacyConfigDownloaded() val workRequestCaptor = ArgumentCaptor.forClass(PeriodicWorkRequest::class.java) verify(workManager).enqueueUniquePeriodicWork( eq("MALICIOUS_SITE_PROTECTION_FILTERS_UPDATE_WORKER_TAG"), - eq(ExistingPeriodicWorkPolicy.UPDATE), + eq(ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE), capture(workRequestCaptor), ) diff --git a/malicious-site-protection/malicious-site-protection-impl/src/test/kotlin/com/duckduckgo/malicioussiteprotection/impl/MaliciousSiteProtectionHashPrefixesUpdateWorkerTest.kt b/malicious-site-protection/malicious-site-protection-impl/src/test/kotlin/com/duckduckgo/malicioussiteprotection/impl/MaliciousSiteProtectionHashPrefixesUpdateWorkerTest.kt index 9046320a79e9..8b0dfd013950 100644 --- a/malicious-site-protection/malicious-site-protection-impl/src/test/kotlin/com/duckduckgo/malicioussiteprotection/impl/MaliciousSiteProtectionHashPrefixesUpdateWorkerTest.kt +++ b/malicious-site-protection/malicious-site-protection-impl/src/test/kotlin/com/duckduckgo/malicioussiteprotection/impl/MaliciousSiteProtectionHashPrefixesUpdateWorkerTest.kt @@ -22,6 +22,7 @@ import org.mockito.Mockito.mock import org.mockito.Mockito.verify import org.mockito.kotlin.capture import org.mockito.kotlin.eq +import org.mockito.kotlin.never import org.mockito.kotlin.whenever @RunWith(AndroidJUnit4::class) @@ -41,6 +42,7 @@ class MaliciousSiteProtectionHashPrefixesUpdateWorkerTest { worker.maliciousSiteRepository = maliciousSiteRepository worker.dispatcherProvider = dispatcherProvider worker.maliciousSiteProtectionFeature = maliciousSiteProtectionFeature + whenever(maliciousSiteProtectionFeature.canUpdateDatasets()).thenReturn(true) } @Test @@ -49,6 +51,17 @@ class MaliciousSiteProtectionHashPrefixesUpdateWorkerTest { val result = worker.doWork() + verify(maliciousSiteRepository, never()).loadHashPrefixes() + assertEquals(success(), result) + } + + @Test + fun doWork_returnsSuccessWhenUpdateDatasetsIsDisabled() = runTest { + whenever(maliciousSiteProtectionFeature.canUpdateDatasets()).thenReturn(false) + + val result = worker.doWork() + + verify(maliciousSiteRepository, never()).loadHashPrefixes() assertEquals(success(), result) } @@ -80,17 +93,17 @@ class MaliciousSiteProtectionHashPrefixesUpdateWorkerSchedulerTest { private val scheduler = MaliciousSiteProtectionHashPrefixesUpdateWorkerScheduler(workManager, maliciousSiteProtectionFeature) @Test - fun onCreate_schedulesWorkerWithUpdateFrequencyFromRCFlag() { + fun onPrivacyConfigDownloaded_schedulesWorkerWithUpdateFrequencyFromRCFlag() { val updateFrequencyMinutes = 15L whenever(maliciousSiteProtectionFeature.getHashPrefixUpdateFrequency()).thenReturn(updateFrequencyMinutes) - scheduler.onCreate(mock()) + scheduler.onPrivacyConfigDownloaded() val workRequestCaptor = ArgumentCaptor.forClass(PeriodicWorkRequest::class.java) verify(workManager).enqueueUniquePeriodicWork( eq("MALICIOUS_SITE_PROTECTION_HASH_PREFIXES_UPDATE_WORKER_TAG"), - eq(ExistingPeriodicWorkPolicy.UPDATE), + eq(ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE), capture(workRequestCaptor), ) From db8b30d1d044c0779ecaa8ef63b097f800c4bbca Mon Sep 17 00:00:00 2001 From: Cris Barreiro Date: Mon, 24 Feb 2025 17:55:12 +0100 Subject: [PATCH 2/2] Improve dataset update scheduling --- ...iciousSiteProtectionFiltersUpdateWorker.kt | 22 +++++++++++++++++-- ...sSiteProtectionHashPrefixesUpdateWorker.kt | 22 +++++++++++++++++-- ...usSiteProtectionFiltersUpdateWorkerTest.kt | 4 ++-- ...eProtectionHashPrefixesUpdateWorkerTest.kt | 2 +- 4 files changed, 43 insertions(+), 7 deletions(-) diff --git a/malicious-site-protection/malicious-site-protection-impl/src/main/kotlin/com/duckduckgo/malicioussiteprotection/impl/MaliciousSiteProtectionFiltersUpdateWorker.kt b/malicious-site-protection/malicious-site-protection-impl/src/main/kotlin/com/duckduckgo/malicioussiteprotection/impl/MaliciousSiteProtectionFiltersUpdateWorker.kt index 7367112b25b9..e35fdb1bc256 100644 --- a/malicious-site-protection/malicious-site-protection-impl/src/main/kotlin/com/duckduckgo/malicioussiteprotection/impl/MaliciousSiteProtectionFiltersUpdateWorker.kt +++ b/malicious-site-protection/malicious-site-protection-impl/src/main/kotlin/com/duckduckgo/malicioussiteprotection/impl/MaliciousSiteProtectionFiltersUpdateWorker.kt @@ -17,6 +17,7 @@ package com.duckduckgo.malicioussiteprotection.impl import android.content.Context +import androidx.lifecycle.LifecycleOwner import androidx.work.BackoffPolicy import androidx.work.CoroutineWorker import androidx.work.ExistingPeriodicWorkPolicy @@ -24,6 +25,7 @@ import androidx.work.PeriodicWorkRequestBuilder import androidx.work.WorkManager import androidx.work.WorkerParameters import com.duckduckgo.anvil.annotations.ContributesWorker +import com.duckduckgo.app.lifecycle.MainProcessLifecycleObserver import com.duckduckgo.common.utils.DispatcherProvider import com.duckduckgo.di.scopes.AppScope import com.duckduckgo.malicioussiteprotection.impl.data.MaliciousSiteRepository @@ -66,14 +68,30 @@ class MaliciousSiteProtectionFiltersUpdateWorker( scope = AppScope::class, boundType = PrivacyConfigCallbackPlugin::class, ) +@ContributesMultibinding( + scope = AppScope::class, + boundType = MainProcessLifecycleObserver::class, +) @SingleInstanceIn(AppScope::class) class MaliciousSiteProtectionFiltersUpdateWorkerScheduler @Inject constructor( private val workManager: WorkManager, private val maliciousSiteProtectionFeature: MaliciousSiteProtectionRCFeature, -) : PrivacyConfigCallbackPlugin { +) : PrivacyConfigCallbackPlugin, MainProcessLifecycleObserver { + + override fun onCreate(owner: LifecycleOwner) { + enqueuePeriodicWork() + } override fun onPrivacyConfigDownloaded() { + enqueuePeriodicWork() + } + + private fun enqueuePeriodicWork() { + if (maliciousSiteProtectionFeature.isFeatureEnabled().not() || maliciousSiteProtectionFeature.canUpdateDatasets().not()) { + workManager.cancelUniqueWork(MALICIOUS_SITE_PROTECTION_FILTERS_UPDATE_WORKER_TAG) + return + } val workerRequest = PeriodicWorkRequestBuilder( maliciousSiteProtectionFeature.getFilterSetUpdateFrequency(), TimeUnit.MINUTES, @@ -83,7 +101,7 @@ class MaliciousSiteProtectionFiltersUpdateWorkerScheduler @Inject constructor( .build() workManager.enqueueUniquePeriodicWork( MALICIOUS_SITE_PROTECTION_FILTERS_UPDATE_WORKER_TAG, - ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE, + ExistingPeriodicWorkPolicy.UPDATE, workerRequest, ) } diff --git a/malicious-site-protection/malicious-site-protection-impl/src/main/kotlin/com/duckduckgo/malicioussiteprotection/impl/MaliciousSiteProtectionHashPrefixesUpdateWorker.kt b/malicious-site-protection/malicious-site-protection-impl/src/main/kotlin/com/duckduckgo/malicioussiteprotection/impl/MaliciousSiteProtectionHashPrefixesUpdateWorker.kt index cf1602983362..891bc32f24af 100644 --- a/malicious-site-protection/malicious-site-protection-impl/src/main/kotlin/com/duckduckgo/malicioussiteprotection/impl/MaliciousSiteProtectionHashPrefixesUpdateWorker.kt +++ b/malicious-site-protection/malicious-site-protection-impl/src/main/kotlin/com/duckduckgo/malicioussiteprotection/impl/MaliciousSiteProtectionHashPrefixesUpdateWorker.kt @@ -17,6 +17,7 @@ package com.duckduckgo.malicioussiteprotection.impl import android.content.Context +import androidx.lifecycle.LifecycleOwner import androidx.work.BackoffPolicy import androidx.work.CoroutineWorker import androidx.work.ExistingPeriodicWorkPolicy @@ -24,6 +25,7 @@ import androidx.work.PeriodicWorkRequestBuilder import androidx.work.WorkManager import androidx.work.WorkerParameters import com.duckduckgo.anvil.annotations.ContributesWorker +import com.duckduckgo.app.lifecycle.MainProcessLifecycleObserver import com.duckduckgo.common.utils.DispatcherProvider import com.duckduckgo.di.scopes.AppScope import com.duckduckgo.malicioussiteprotection.impl.data.MaliciousSiteRepository @@ -66,14 +68,30 @@ class MaliciousSiteProtectionHashPrefixesUpdateWorker( scope = AppScope::class, boundType = PrivacyConfigCallbackPlugin::class, ) +@ContributesMultibinding( + scope = AppScope::class, + boundType = MainProcessLifecycleObserver::class, +) @SingleInstanceIn(AppScope::class) class MaliciousSiteProtectionHashPrefixesUpdateWorkerScheduler @Inject constructor( private val workManager: WorkManager, private val maliciousSiteProtectionFeature: MaliciousSiteProtectionRCFeature, -) : PrivacyConfigCallbackPlugin { +) : PrivacyConfigCallbackPlugin, MainProcessLifecycleObserver { + + override fun onCreate(owner: LifecycleOwner) { + enqueuePeriodicWork() + } override fun onPrivacyConfigDownloaded() { + enqueuePeriodicWork() + } + + private fun enqueuePeriodicWork() { + if (maliciousSiteProtectionFeature.isFeatureEnabled().not() || maliciousSiteProtectionFeature.canUpdateDatasets().not()) { + workManager.cancelUniqueWork(MALICIOUS_SITE_PROTECTION_HASH_PREFIXES_UPDATE_WORKER_TAG) + return + } val workerRequest = PeriodicWorkRequestBuilder( maliciousSiteProtectionFeature.getHashPrefixUpdateFrequency(), TimeUnit.MINUTES, @@ -83,7 +101,7 @@ class MaliciousSiteProtectionHashPrefixesUpdateWorkerScheduler @Inject construct .build() workManager.enqueueUniquePeriodicWork( MALICIOUS_SITE_PROTECTION_HASH_PREFIXES_UPDATE_WORKER_TAG, - ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE, + ExistingPeriodicWorkPolicy.UPDATE, workerRequest, ) } diff --git a/malicious-site-protection/malicious-site-protection-impl/src/test/kotlin/com/duckduckgo/malicioussiteprotection/impl/MaliciousSiteProtectionFiltersUpdateWorkerTest.kt b/malicious-site-protection/malicious-site-protection-impl/src/test/kotlin/com/duckduckgo/malicioussiteprotection/impl/MaliciousSiteProtectionFiltersUpdateWorkerTest.kt index 3e0cc5e2785c..be94c5f6955d 100644 --- a/malicious-site-protection/malicious-site-protection-impl/src/test/kotlin/com/duckduckgo/malicioussiteprotection/impl/MaliciousSiteProtectionFiltersUpdateWorkerTest.kt +++ b/malicious-site-protection/malicious-site-protection-impl/src/test/kotlin/com/duckduckgo/malicioussiteprotection/impl/MaliciousSiteProtectionFiltersUpdateWorkerTest.kt @@ -93,7 +93,7 @@ class MaliciousSiteProtectionFiltersUpdateWorkerSchedulerTest { private val scheduler = MaliciousSiteProtectionFiltersUpdateWorkerScheduler(workManager, maliciousSiteProtectionFeature) @Test - fun onPrivacyConfigDownloaded_schedulesWorkerWithUpdateFrequencyFromRCFlagAndReenqueuePolicy() { + fun onPrivacyConfigDownloaded_schedulesWorkerWithUpdateFrequencyFromRCFlagAndUpdatePolicy() { val updateFrequencyMinutes = 15L whenever(maliciousSiteProtectionFeature.getFilterSetUpdateFrequency()).thenReturn(updateFrequencyMinutes) @@ -103,7 +103,7 @@ class MaliciousSiteProtectionFiltersUpdateWorkerSchedulerTest { val workRequestCaptor = ArgumentCaptor.forClass(PeriodicWorkRequest::class.java) verify(workManager).enqueueUniquePeriodicWork( eq("MALICIOUS_SITE_PROTECTION_FILTERS_UPDATE_WORKER_TAG"), - eq(ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE), + eq(ExistingPeriodicWorkPolicy.UPDATE), capture(workRequestCaptor), ) diff --git a/malicious-site-protection/malicious-site-protection-impl/src/test/kotlin/com/duckduckgo/malicioussiteprotection/impl/MaliciousSiteProtectionHashPrefixesUpdateWorkerTest.kt b/malicious-site-protection/malicious-site-protection-impl/src/test/kotlin/com/duckduckgo/malicioussiteprotection/impl/MaliciousSiteProtectionHashPrefixesUpdateWorkerTest.kt index 8b0dfd013950..242a6296c89c 100644 --- a/malicious-site-protection/malicious-site-protection-impl/src/test/kotlin/com/duckduckgo/malicioussiteprotection/impl/MaliciousSiteProtectionHashPrefixesUpdateWorkerTest.kt +++ b/malicious-site-protection/malicious-site-protection-impl/src/test/kotlin/com/duckduckgo/malicioussiteprotection/impl/MaliciousSiteProtectionHashPrefixesUpdateWorkerTest.kt @@ -103,7 +103,7 @@ class MaliciousSiteProtectionHashPrefixesUpdateWorkerSchedulerTest { val workRequestCaptor = ArgumentCaptor.forClass(PeriodicWorkRequest::class.java) verify(workManager).enqueueUniquePeriodicWork( eq("MALICIOUS_SITE_PROTECTION_HASH_PREFIXES_UPDATE_WORKER_TAG"), - eq(ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE), + eq(ExistingPeriodicWorkPolicy.UPDATE), capture(workRequestCaptor), )