Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Unverified Commit 3bd3f56e authored by Ricki Hirner's avatar Ricki Hirner Committed by GitHub
Browse files

Fix DeadObjectException handling in SyncManager and Syncer (#1834)

- Update SyncManager to handle LocalStorageException with DeadObjectException cause
- Refactor Syncer to catch all exceptions and handle specific cases
parent 52631723
Loading
Loading
Loading
Loading
+4 −3
Original line number Diff line number Diff line
@@ -256,9 +256,10 @@ abstract class SyncManager<ResourceType: LocalResource, out CollectionType: Loca
            }

            when (e) {
                // DeadObjectException (may occur when syncing takes too long and process is demoted to cached):
                // re-throw to base Syncer → will cause soft error and restart the sync process
                is DeadObjectException ->
                /* LocalStorageException with cause DeadObjectException may occur when syncing takes too long
                and process is demoted to cached. In this case, we re-throw to the base Syncer which will
                treat it as a soft error and re-schedule the sync process. */
                is LocalStorageException if e.cause is DeadObjectException ->
                    throw e

                // sync was cancelled or account has been removed: re-throw to Syncer
+21 −10
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@ import at.bitfire.davdroid.repository.DavServiceRepository
import at.bitfire.davdroid.resource.LocalCollection
import at.bitfire.davdroid.resource.LocalDataStore
import at.bitfire.davdroid.sync.account.InvalidAccountException
import at.bitfire.synctools.storage.LocalStorageException
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.runBlocking
import java.util.logging.Level
@@ -259,18 +260,28 @@ abstract class Syncer<StoreType: LocalDataStore<CollectionType>, CollectionType:
                if (runSync)
                    sync(provider)
                Unit
            } catch (e: DeadObjectException) {

            } catch (e: Exception) {
                /* Handle sync exceptions. Note that most exceptions that occur during synchronization of a specific
                collection are already handled in SyncManager. The exceptions here usually
                - have occurred during Syncer operation (for instance when creating/deleting local collections),
                - or have been re-thrown from SyncManager (like the wrapped DeadObjectException). */
                when (e) {
                    /* 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". */
                    is LocalStorageException if e.cause is DeadObjectException -> {
                        logger.log(Level.WARNING, "Received DeadObjectException, treating as soft error", e)
                        syncResult.numDeadObjectExceptions++
                    }

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

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

            } finally {
                logger.info("${dataStore.authority} sync of $account finished")