Fix potential thread-safety issue when changing backends
This commit is contained in:
parent
3d9eca0d40
commit
2957678465
5 changed files with 36 additions and 12 deletions
|
@ -25,7 +25,10 @@ class BackendManager(
|
||||||
backendFactory: BackendFactory,
|
backendFactory: BackendFactory,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
@Volatile
|
||||||
private var mBackend: Backend?
|
private var mBackend: Backend?
|
||||||
|
|
||||||
|
@Volatile
|
||||||
private var mBackendProperties: BackendProperties<*>?
|
private var mBackendProperties: BackendProperties<*>?
|
||||||
|
|
||||||
val backend: Backend
|
val backend: Backend
|
||||||
|
@ -81,6 +84,8 @@ class BackendManager(
|
||||||
* IMPORTANT: Do no call this while current plugins are being used,
|
* IMPORTANT: Do no call this while current plugins are being used,
|
||||||
* e.g. while backup/restore operation is still running.
|
* e.g. while backup/restore operation is still running.
|
||||||
*/
|
*/
|
||||||
|
@WorkerThread
|
||||||
|
@Synchronized
|
||||||
fun <T> changePlugins(
|
fun <T> changePlugins(
|
||||||
backend: Backend,
|
backend: Backend,
|
||||||
storageProperties: BackendProperties<T>,
|
storageProperties: BackendProperties<T>,
|
||||||
|
|
|
@ -90,6 +90,7 @@ internal class SafHandler(
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@WorkerThread
|
||||||
fun setPlugin(safProperties: SafProperties) {
|
fun setPlugin(safProperties: SafProperties) {
|
||||||
backendManager.changePlugins(
|
backendManager.changePlugins(
|
||||||
backend = backendFactory.createSafBackend(safProperties),
|
backend = backendFactory.createSafBackend(safProperties),
|
||||||
|
|
|
@ -87,6 +87,7 @@ internal class WebDavHandler(
|
||||||
settingsManager.saveWebDavConfig(properties.config)
|
settingsManager.saveWebDavConfig(properties.config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@WorkerThread
|
||||||
fun setPlugin(properties: WebDavProperties, backend: Backend) {
|
fun setPlugin(properties: WebDavProperties, backend: Backend) {
|
||||||
backendManager.changePlugins(
|
backendManager.changePlugins(
|
||||||
backend = backend,
|
backend = backend,
|
||||||
|
|
|
@ -7,6 +7,7 @@ package com.stevesoltys.seedvault.repo
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Context.MODE_APPEND
|
import android.content.Context.MODE_APPEND
|
||||||
|
import androidx.annotation.WorkerThread
|
||||||
import com.stevesoltys.seedvault.MemoryLogger
|
import com.stevesoltys.seedvault.MemoryLogger
|
||||||
import com.stevesoltys.seedvault.proto.Snapshot
|
import com.stevesoltys.seedvault.proto.Snapshot
|
||||||
import com.stevesoltys.seedvault.proto.Snapshot.Blob
|
import com.stevesoltys.seedvault.proto.Snapshot.Blob
|
||||||
|
@ -90,6 +91,7 @@ class BlobCache(
|
||||||
* * changing to a different backup to prevent usage of blobs that don't exist there
|
* * changing to a different backup to prevent usage of blobs that don't exist there
|
||||||
* * uploading a new snapshot to prevent the persistent cache from growing indefinitely
|
* * uploading a new snapshot to prevent the persistent cache from growing indefinitely
|
||||||
*/
|
*/
|
||||||
|
@WorkerThread
|
||||||
fun clearLocalCache() {
|
fun clearLocalCache() {
|
||||||
log.info { "Clearing local cache..." }
|
log.info { "Clearing local cache..." }
|
||||||
context.deleteFile(CACHE_FILE_NAME)
|
context.deleteFile(CACHE_FILE_NAME)
|
||||||
|
|
|
@ -10,6 +10,7 @@ import android.app.backup.IBackupManager
|
||||||
import android.app.job.JobInfo
|
import android.app.job.JobInfo
|
||||||
import android.os.UserHandle
|
import android.os.UserHandle
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
import androidx.annotation.UiThread
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import androidx.work.ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE
|
import androidx.work.ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE
|
||||||
import com.stevesoltys.seedvault.R
|
import com.stevesoltys.seedvault.R
|
||||||
|
@ -23,6 +24,7 @@ import com.stevesoltys.seedvault.worker.AppBackupWorker
|
||||||
import com.stevesoltys.seedvault.worker.BackupRequester.Companion.requestFilesAndAppBackup
|
import com.stevesoltys.seedvault.worker.BackupRequester.Companion.requestFilesAndAppBackup
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
import org.calyxos.backup.storage.api.StorageBackup
|
import org.calyxos.backup.storage.api.StorageBackup
|
||||||
import org.calyxos.backup.storage.backup.BackupJobService
|
import org.calyxos.backup.storage.backup.BackupJobService
|
||||||
import org.calyxos.seedvault.core.backends.Backend
|
import org.calyxos.seedvault.core.backends.Backend
|
||||||
|
@ -46,25 +48,38 @@ internal class BackupStorageViewModel(
|
||||||
|
|
||||||
override val isRestoreOperation = false
|
override val isRestoreOperation = false
|
||||||
|
|
||||||
|
@UiThread
|
||||||
override fun onSafUriSet(safProperties: SafProperties) {
|
override fun onSafUriSet(safProperties: SafProperties) {
|
||||||
safHandler.save(safProperties)
|
safHandler.save(safProperties)
|
||||||
safHandler.setPlugin(safProperties)
|
viewModelScope.launch {
|
||||||
if (safProperties.isUsb) {
|
withContext(Dispatchers.IO) {
|
||||||
// disable storage backup if new storage is on USB
|
safHandler.setPlugin(safProperties)
|
||||||
cancelBackupWorkers()
|
}
|
||||||
} else {
|
withContext(Dispatchers.Main) { // UiThread
|
||||||
// enable it, just in case the previous storage was on USB,
|
if (safProperties.isUsb) {
|
||||||
// also to update the network requirement of the new storage
|
// disable storage backup if new storage is on USB
|
||||||
scheduleBackupWorkers()
|
cancelBackupWorkers()
|
||||||
|
} else {
|
||||||
|
// enable it, just in case the previous storage was on USB,
|
||||||
|
// also to update the network requirement of the new storage
|
||||||
|
scheduleBackupWorkers()
|
||||||
|
}
|
||||||
|
onStorageLocationSet(safProperties.isUsb)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
onStorageLocationSet(safProperties.isUsb)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onWebDavConfigSet(properties: WebDavProperties, backend: Backend) {
|
override fun onWebDavConfigSet(properties: WebDavProperties, backend: Backend) {
|
||||||
webdavHandler.save(properties)
|
webdavHandler.save(properties)
|
||||||
webdavHandler.setPlugin(properties, backend)
|
viewModelScope.launch {
|
||||||
scheduleBackupWorkers()
|
withContext(Dispatchers.IO) {
|
||||||
onStorageLocationSet(isUsb = false)
|
webdavHandler.setPlugin(properties, backend)
|
||||||
|
}
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
scheduleBackupWorkers()
|
||||||
|
onStorageLocationSet(isUsb = false)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onStorageLocationSet(isUsb: Boolean) {
|
private fun onStorageLocationSet(isUsb: Boolean) {
|
||||||
|
|
Loading…
Reference in a new issue