Skip to content

Commit

Permalink
Use our own SyncResult data class
Browse files Browse the repository at this point in the history
  • Loading branch information
sunkup committed Oct 22, 2024
1 parent 1802740 commit 9869f88
Show file tree
Hide file tree
Showing 15 changed files with 76 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ package at.bitfire.davdroid.sync

import android.accounts.Account
import android.content.Context
import android.content.SyncResult
import android.util.Log
import androidx.core.app.NotificationManagerCompat
import androidx.hilt.work.HiltWorkerFactory
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ package at.bitfire.davdroid.sync

import android.accounts.Account
import android.content.ContentProviderClient
import android.content.SyncResult
import at.bitfire.davdroid.db.Collection
import at.bitfire.davdroid.sync.account.TestAccountAuthenticator
import dagger.assisted.Assisted
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
package at.bitfire.davdroid.sync

import android.accounts.Account
import android.content.SyncResult
import at.bitfire.dav4jvm.DavCollection
import at.bitfire.dav4jvm.MultiResponseCallback
import at.bitfire.dav4jvm.Response
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ package at.bitfire.davdroid.sync

import android.accounts.Account
import android.content.ContentProviderClient
import android.content.SyncResult
import android.provider.ContactsContract
import at.bitfire.davdroid.db.Collection
import at.bitfire.davdroid.db.Service
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
package at.bitfire.davdroid.sync

import android.accounts.Account
import android.content.SyncResult
import android.text.format.Formatter
import at.bitfire.dav4jvm.DavCalendar
import at.bitfire.dav4jvm.MultiResponseCallback
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ package at.bitfire.davdroid.sync
import android.accounts.Account
import android.content.ContentProviderClient
import android.content.ContentUris
import android.content.SyncResult
import android.provider.CalendarContract
import at.bitfire.davdroid.db.Collection
import at.bitfire.davdroid.db.Service
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ package at.bitfire.davdroid.sync
import android.accounts.Account
import android.content.ContentProviderClient
import android.content.ContentResolver
import android.content.SyncResult
import android.os.Build
import android.text.format.Formatter
import at.bitfire.dav4jvm.DavAddressBook
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
package at.bitfire.davdroid.sync

import android.accounts.Account
import android.content.SyncResult
import android.text.format.Formatter
import at.bitfire.dav4jvm.DavCalendar
import at.bitfire.dav4jvm.MultiResponseCallback
Expand Down
3 changes: 1 addition & 2 deletions app/src/main/kotlin/at/bitfire/davdroid/sync/JtxSyncer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import android.accounts.Account
import android.accounts.AccountManager
import android.content.ContentProviderClient
import android.content.ContentUris
import android.content.SyncResult
import android.os.Build
import at.bitfire.davdroid.db.Collection
import at.bitfire.davdroid.db.Service
Expand Down Expand Up @@ -54,7 +53,7 @@ class JtxSyncer @AssistedInject constructor(
TaskProvider.checkVersion(context, TaskProvider.ProviderName.JtxBoard)
} catch (e: TaskProvider.ProviderTooOldException) {
tasksAppManager.get().notifyProviderTooOld(e)
syncResult.databaseError = true
syncResult.contentProviderError = true
return false // Don't sync
}

Expand Down
9 changes: 4 additions & 5 deletions app/src/main/kotlin/at/bitfire/davdroid/sync/SyncManager.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import android.app.PendingIntent
import android.content.ContentUris
import android.content.Context
import android.content.Intent
import android.content.SyncResult
import android.net.Uri
import android.os.DeadObjectException
import android.os.RemoteException
Expand Down Expand Up @@ -333,7 +332,7 @@ abstract class SyncManager<ResourceType: LocalResource<*>, out CollectionType: L
logger.log(Level.WARNING, "Got 503 Service unavailable, trying again later", e)
// determine when to retry
syncResult.delayUntil = getDelayUntil(e.retryAfter).epochSecond
syncResult.stats.numIoExceptions++ // Indicate a soft error occurred
syncResult.stats.numServiceUnavailableExceptions++ // Indicate a soft error occurred
}

// all others
Expand Down Expand Up @@ -788,19 +787,19 @@ abstract class SyncManager<ResourceType: LocalResource<*>, out CollectionType: L
is HttpException, is DavException -> {
logger.log(Level.SEVERE, "HTTP/DAV exception", e)
message = context.getString(R.string.sync_error_http_dav, e.localizedMessage)
syncResult.stats.numParseExceptions++ // numIoExceptions would indicate a soft error
syncResult.stats.numHttpExceptions++
}

is CalendarStorageException, is ContactsStorageException, is RemoteException -> {
logger.log(Level.SEVERE, "Couldn't access local storage", e)
message = context.getString(R.string.sync_error_local_storage, e.localizedMessage)
syncResult.databaseError = true
syncResult.localStorageError = true
}

else -> {
logger.log(Level.SEVERE, "Unclassified sync error", e)
message = e.localizedMessage ?: e::class.java.simpleName
syncResult.stats.numParseExceptions++
syncResult.stats.numUnclassifiedErrors++
}
}

Expand Down
63 changes: 63 additions & 0 deletions app/src/main/kotlin/at/bitfire/davdroid/sync/SyncResult.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package at.bitfire.davdroid.sync

/**
* This class is used to communicate the results of a sync operation from [Syncer]s to the
* [at.bitfire.davdroid.sync.worker.BaseSyncWorker]. Based on the values here the
* [at.bitfire.davdroid.sync.worker.BaseSyncWorker] will determine the run ability of the sync and
* whether or not there will be retries. See the implementation of
* [at.bitfire.davdroid.sync.worker.BaseSyncWorker.doSyncWork] for details.
*/
data class SyncResult(
var contentProviderError: Boolean = false,
var localStorageError: Boolean = false,
var delayUntil: Long = 0,
val stats: SyncStats = SyncStats()
) {

/**
* Whether a hard error occurred.
*/
fun hasHardError(): Boolean =
contentProviderError
|| localStorageError
|| stats.numAuthExceptions > 0
|| stats.numHttpExceptions > 0
|| stats.numUnclassifiedErrors > 0

/**
* Whether a soft error occurred.
*/
fun hasSoftError(): Boolean =
stats.numDeadObjectExceptions > 0
|| stats.numIoExceptions > 0
|| stats.numServiceUnavailableExceptions > 0

/**
* Whether a hard or a soft error occurred.
*/
fun hasError(): Boolean =
hasHardError() || hasSoftError()

/**
* Holds statistics about the sync operation. Used to determine retries. Also useful for
* debugging and customer support when logged.
*/
data class SyncStats(
// Stats
var numDeletes: Long = 0,
var numEntries: Long = 0,
var numInserts: Long = 0,
var numSkippedEntries: Long = 0,
var numUpdates: Long = 0,

// Hard errors
var numAuthExceptions: Long = 0,
var numHttpExceptions: Long = 0,
var numUnclassifiedErrors: Long = 0,

// Soft errors
var numDeadObjectExceptions: Long = 0,
var numIoExceptions: Long = 0,
var numServiceUnavailableExceptions: Long = 0
)
}
7 changes: 3 additions & 4 deletions app/src/main/kotlin/at/bitfire/davdroid/sync/Syncer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ package at.bitfire.davdroid.sync
import android.accounts.Account
import android.content.ContentProviderClient
import android.content.Context
import android.content.SyncResult
import android.os.DeadObjectException
import androidx.annotation.VisibleForTesting
import at.bitfire.davdroid.InvalidAccountException
Expand Down Expand Up @@ -282,7 +281,7 @@ abstract class Syncer<CollectionType: LocalCollection<*>>(
- the content provider is not available at all, for instance because the respective
system app, like "calendar storage" is disabled */
logger.warning("Couldn't connect to content provider of authority $authority")
syncResult.stats.numParseExceptions++ // hard sync error
syncResult.contentProviderError = true

return // Don't continue without provider
}
Expand All @@ -297,14 +296,14 @@ abstract class Syncer<CollectionType: LocalCollection<*>>(
/* May happen when the remote process dies or (since Android 14) when IPC (for instance with the calendar provider)
is suddenly forbidden because our sync process was demoted from a "service process" to a "cached process". */
logger.log(Level.WARNING, "Received DeadObjectException, treating as soft error", e)
syncResult.stats.numIoExceptions++
syncResult.stats.numDeadObjectExceptions++

} catch (e: InvalidAccountException) {
logger.log(Level.WARNING, "Account was removed during synchronization", e)

} catch (e: Exception) {
logger.log(Level.SEVERE, "Couldn't sync $authority", e)
syncResult.stats.numParseExceptions++ // Hard sync error
syncResult.stats.numUnclassifiedErrors++ // Hard sync error

} finally {
if (httpClient.isInitialized())
Expand Down
3 changes: 1 addition & 2 deletions app/src/main/kotlin/at/bitfire/davdroid/sync/TaskSyncer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import android.accounts.Account
import android.accounts.AccountManager
import android.content.ContentProviderClient
import android.content.ContentUris
import android.content.SyncResult
import android.os.Build
import at.bitfire.davdroid.db.Collection
import at.bitfire.davdroid.db.Service
Expand Down Expand Up @@ -52,7 +51,7 @@ class TaskSyncer @AssistedInject constructor(
TaskProvider.checkVersion(context, providerName)
} catch (e: TaskProvider.ProviderTooOldException) {
tasksAppManager.get().notifyProviderTooOld(e)
syncResult.databaseError = true
syncResult.contentProviderError = true
return false // Don't sync
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
package at.bitfire.davdroid.sync

import android.accounts.Account
import android.content.SyncResult
import android.text.format.Formatter
import at.bitfire.dav4jvm.DavCalendar
import at.bitfire.dav4jvm.MultiResponseCallback
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ package at.bitfire.davdroid.sync.worker
import android.accounts.Account
import android.content.ContentResolver
import android.content.Context
import android.content.SyncResult
import android.os.Build
import android.provider.CalendarContract
import androidx.annotation.IntDef
Expand All @@ -27,20 +26,21 @@ import at.bitfire.davdroid.sync.AddressBookSyncer
import at.bitfire.davdroid.sync.CalendarSyncer
import at.bitfire.davdroid.sync.JtxSyncer
import at.bitfire.davdroid.sync.SyncConditions
import at.bitfire.davdroid.sync.SyncResult
import at.bitfire.davdroid.sync.SyncUtils
import at.bitfire.davdroid.sync.Syncer
import at.bitfire.davdroid.sync.TaskSyncer
import at.bitfire.davdroid.ui.NotificationRegistry
import at.bitfire.ical4android.TaskProvider
import java.util.Collections
import java.util.logging.Logger
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.runInterruptible
import kotlinx.coroutines.withContext
import java.util.Collections
import java.util.logging.Logger
import javax.inject.Inject

abstract class BaseSyncWorker(
context: Context,
Expand Down

0 comments on commit 9869f88

Please sign in to comment.