I have an application with a SyncAdapter
. Additionally to the normal synchronization I trigger a USER_READ
event with which I just pass a Bundle
to the adapter without persisting it:
Bundle settingsBundle = new Bundle();
settingsBundle.putString(SyncAdapter.USER_READ, uid);
ContentResolver.requestSync(account, authority, settingsBundle);
This will correctly call my synchronization routine sometime in the future. Every uid
set in the Bundle
will trigger its own run and everything gets synced as expected.
If now the connection is bad, or the request times out, then I set a soft error:
syncResult.stats.numIoExceptions += 1;
which will cause the request to be repeated later. This also works just fine.
How long do these SyncRequests / Bundles get persisted?
The documentation states, that encountering a soft error will cause an exponentional backoff and that the sync will be run some time later.
Given the connection is bad and the synchronization fails multiple times with soft errors: I would like to know if just enqueuing a sync request is enough, or if I have to provide some sort of persistence myself to ensure requests being sent at some point.
I had to dig in Android runtime source a little to find an answer to your question. Let's start from the first part of the question.
Will it [sync] be canceled at some point? After multiple soft errors?
And the answer is probably no, until one of the following conditions is met:
SyncManager
not to reschedule sync by starting SyncAdapter
with ContentResolver.SYNC_EXTRAS_DO_NOT_RETRY
SyncResult.tooManyRetries
to true
and sync isn't upload-onlySyncResult.tooManyDeletions
to true
, don't set SyncStats.numInserts
or SyncStats.numUpdates
to non-null values, and sync isn't upload-onlySo multiple soft errors don't cancel sync and here's why.
Handling all sync events starts in SyncManager.SyncHandler.handleMessage()
method and continues in SyncManager.runSyncFinishedOrCanceledH()
method. The first argument of runSyncFinishedOrCanceledH()
is SyncResult
, which can be null
. It's not null
either when sync is finished or when SyncAdapter
service is disconnected, which is a soft error. And it's null
when sync is cancelled, expired (runs more than 30 minutes), not using network for more than 1 minute, and in another case I don't fully understand.
In case SyncResult
is not null
and sync finished with errors, SyncManager
tries to reschedule sync by calling maybeRescheduleSync()
. This methods checks some flags and sync results, like ContentResolver.SYNC_EXTRAS_DO_NOT_RETRY
and SyncResult.tooManyRetries
do decide if it needs to reschedule sync. And after SyncManager
checks that sync finished with a soft error syncResult.hasSoftError()
it reschedules sync without any additional checks.
And now the second part of the question.
Will it [sync] be enqueued again after a reboot of the device?
Yes, it will. When SystemServer
initializes, it creates ContentService
and then calls its systemReady()
method, which in its turn creates SyncManager
. SyncManager
in its constructor creates SyncStorageEngine
, which reads all pending operations in its constructor including extra bundles. That's why a set of types allowed in sync bundles is very limited. And when user is starting all pending operations are added to SynqQueue
by calling SyncQueue.addPendingOperations()
.
This answer is the result of my analysis of Android code so I cannot guarantee it's 100% correct. But you can use this information as a starting point for your own research.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With