SyncManager 会保留 bundle 多长时间?

How long do bundles get persisted by SyncManager?

我有一个 SyncAdapter 的应用程序。除了正常同步之外,我还触发了一个 USER_READ 事件,我只是将 Bundle 传递给适配器而不保留它:

Bundle settingsBundle = new Bundle();
settingsBundle.putString(SyncAdapter.USER_READ, uid);
ContentResolver.requestSync(account, authority, settingsBundle);

这将在将来的某个时候正确调用我的同步例程。在 Bundle 中设置的每个 uid 都会触发它自己的 运行 并且所有内容都会按预期同步。

如果现在连接不好,或者请求超时,那么我设置一个软错误:

syncResult.stats.numIoExceptions += 1;

这将导致稍后重复请求。这也很好用。


这些 SyncRequests/Bundle 会持续多久?

文档指出,遇到软错误将导致指数退避,并且同步将在 运行 一段时间后。

考虑到连接不好并且同步因软错误多次失败:我想知道仅将同步请求排入队列是否足够,或者我是否必须自己提供某种持久性以确保发送请求在某个时候。

我不得不深入研究 Android 运行时源代码才能找到您问题的答案。让我们从问题的第一部分开始。

Will it [sync] be canceled at some point? After multiple soft errors?

在满足以下条件之一之前,答案可能是否定的:

  • 同步被取消
  • 您要求 SyncManager 不要通过从 SyncAdapter 开始与 ContentResolver.SYNC_EXTRAS_DO_NOT_RETRY
  • 重新安排同步
  • 您将 SyncResult.tooManyRetries 设置为 true 并且同步不是仅上传
  • 您将 SyncResult.tooManyDeletions 设置为 true,不要将 SyncStats.numInsertsSyncStats.numUpdates 设置为非空值,并且同步不是仅上传
  • sync 没有软错误但有一些硬错误,而且它不是仅上传
  • 同步运行超过 30 分钟
  • 同步未使用网络超过 1 分钟

所以多个软错误不会取消同步,原因如下。

处理所有同步事件从 SyncManager.SyncHandler.handleMessage() method and continues in SyncManager.runSyncFinishedOrCanceledH() 方法开始。 runSyncFinishedOrCanceledH()的第一个参数是SyncResult,可以是null。同步完成后或SyncAdapter服务断开时都不是null,这是一个软错误。还有null当同步被取消,过期(运行超过30分钟),不使用网络超过1分钟,还有一种情况我不完全理解。

如果 SyncResult 不是 null 并且同步完成时出现错误,SyncManager 会尝试通过调用 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() 重新安排同步,它会在不进行任何额外检查的情况下重新安排同步。

现在是问题的第二部分。

Will it [sync] be enqueued again after a reboot of the device?

是的,会的。当 SystemServer 初始化时,它创建 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().

这个答案是我分析 Android 代码的结果,所以我不能保证它 100% 正确。但您可以将这些信息作为您自己研究的起点。