@@ -205,6 +205,9 @@ public void onReceive(Context context, Intent intent) {
205205
206206 private final PowerManager mPowerManager ;
207207
208+ // Use this as a random offset to seed all periodic syncs
209+ private int mSyncRandomOffsetMillis ;
210+
208211 private static final long SYNC_ALARM_TIMEOUT_MIN = 30 * 1000 ; // 30 seconds
209212 private static final long SYNC_ALARM_TIMEOUT_MAX = 2 * 60 * 60 * 1000 ; // two hours
210213
@@ -438,6 +441,9 @@ public void onStatusChanged(int which) {
438441 // do this synchronously to ensure we have the accounts before this call returns
439442 onAccountsUpdated (null );
440443 }
444+
445+ // Pick a random second in a day to seed all periodic syncs
446+ mSyncRandomOffsetMillis = mSyncStorageEngine .getSyncRandomOffset () * 1000 ;
441447 }
442448
443449 /**
@@ -666,6 +672,7 @@ private void sendSyncAlarmMessage() {
666672
667673 private void sendCheckAlarmsMessage () {
668674 if (Log .isLoggable (TAG , Log .VERBOSE )) Log .v (TAG , "sending MESSAGE_CHECK_ALARMS" );
675+ mSyncHandler .removeMessages (SyncHandler .MESSAGE_CHECK_ALARMS );
669676 mSyncHandler .sendEmptyMessage (SyncHandler .MESSAGE_CHECK_ALARMS );
670677 }
671678
@@ -714,6 +721,8 @@ private void clearBackoffSetting(SyncOperation op) {
714721 }
715722
716723 private void increaseBackoffSetting (SyncOperation op ) {
724+ // TODO: Use this function to align it to an already scheduled sync
725+ // operation in the specified window
717726 final long now = SystemClock .elapsedRealtime ();
718727
719728 final Pair <Long , Long > previousSettings =
@@ -1060,6 +1069,8 @@ protected void dumpSyncState(PrintWriter pw) {
10601069 final long now = SystemClock .elapsedRealtime ();
10611070 pw .print ("now: " ); pw .print (now );
10621071 pw .println (" (" + formatTime (System .currentTimeMillis ()) + ")" );
1072+ pw .print ("offset: " ); pw .print (DateUtils .formatElapsedTime (mSyncRandomOffsetMillis /1000 ));
1073+ pw .println (" (HH:MM:SS)" );
10631074 pw .print ("uptime: " ); pw .print (DateUtils .formatElapsedTime (now /1000 ));
10641075 pw .println (" (HH:MM:SS)" );
10651076 pw .print ("time spent syncing: " );
@@ -1771,6 +1782,9 @@ private long scheduleReadyPeriodicSyncs() {
17711782 AccountAndUser [] accounts = mAccounts ;
17721783
17731784 final long nowAbsolute = System .currentTimeMillis ();
1785+ final long shiftedNowAbsolute = (0 < nowAbsolute - mSyncRandomOffsetMillis )
1786+ ? (nowAbsolute - mSyncRandomOffsetMillis ) : 0 ;
1787+
17741788 ArrayList <SyncStorageEngine .AuthorityInfo > infos = mSyncStorageEngine .getAuthorities ();
17751789 for (SyncStorageEngine .AuthorityInfo info : infos ) {
17761790 // skip the sync if the account of this operation no longer exists
@@ -1792,16 +1806,32 @@ private long scheduleReadyPeriodicSyncs() {
17921806 SyncStatusInfo status = mSyncStorageEngine .getOrCreateSyncStatus (info );
17931807 for (int i = 0 , N = info .periodicSyncs .size (); i < N ; i ++) {
17941808 final Bundle extras = info .periodicSyncs .get (i ).first ;
1795- final Long periodInSeconds = info .periodicSyncs .get (i ).second ;
1809+ final Long periodInMillis = info .periodicSyncs .get (i ).second * 1000 ;
17961810 // find when this periodic sync was last scheduled to run
17971811 final long lastPollTimeAbsolute = status .getPeriodicSyncTime (i );
1798- // compute when this periodic sync should next run - this can be in the future
1799- // for example if the user changed the time, synced and changed back.
1800- final long nextPollTimeAbsolute = lastPollTimeAbsolute > nowAbsolute
1801- ? nowAbsolute
1802- : lastPollTimeAbsolute + periodInSeconds * 1000 ;
1803- // if it is ready to run then schedule it and mark it as having been scheduled
1804- if (nextPollTimeAbsolute <= nowAbsolute ) {
1812+
1813+ long remainingMillis
1814+ = periodInMillis - (shiftedNowAbsolute % periodInMillis );
1815+
1816+ /*
1817+ * Sync scheduling strategy:
1818+ * Set the next periodic sync based on a random offset (in seconds).
1819+ *
1820+ * Also sync right now if any of the following cases hold
1821+ * and mark it as having been scheduled
1822+ *
1823+ * Case 1: This sync is ready to run now.
1824+ * Case 2: If the lastPollTimeAbsolute is in the future,
1825+ * sync now and reinitialize. This can happen for
1826+ * example if the user changed the time, synced and
1827+ * changed back.
1828+ * Case 3: If we failed to sync at the last scheduled time
1829+ */
1830+ if (remainingMillis == periodInMillis // Case 1
1831+ || lastPollTimeAbsolute > nowAbsolute // Case 2
1832+ || (nowAbsolute - lastPollTimeAbsolute
1833+ >= periodInMillis )) { // Case 3
1834+ // Sync now
18051835 final Pair <Long , Long > backoff = mSyncStorageEngine .getBackoff (
18061836 info .account , info .userId , info .authority );
18071837 final RegisteredServicesCache .ServiceInfo <SyncAdapterType > syncAdapterInfo =
@@ -1819,12 +1849,13 @@ private long scheduleReadyPeriodicSyncs() {
18191849 info .account , info .userId , info .authority ),
18201850 syncAdapterInfo .type .allowParallelSyncs ()));
18211851 status .setPeriodicSyncTime (i , nowAbsolute );
1822- } else {
1823- // it isn't ready to run, remember this time if it is earlier than
1824- // earliestFuturePollTime
1825- if (nextPollTimeAbsolute < earliestFuturePollTime ) {
1826- earliestFuturePollTime = nextPollTimeAbsolute ;
1827- }
1852+ }
1853+ // Compute when this periodic sync should next run
1854+ final long nextPollTimeAbsolute = nowAbsolute + remainingMillis ;
1855+
1856+ // remember this time if it is earlier than earliestFuturePollTime
1857+ if (nextPollTimeAbsolute < earliestFuturePollTime ) {
1858+ earliestFuturePollTime = nextPollTimeAbsolute ;
18281859 }
18291860 }
18301861 }
0 commit comments