@@ -204,6 +204,9 @@ public void onReceive(Context context, Intent intent) {
204204
205205 private final PowerManager mPowerManager ;
206206
207+ // Use this as a random offset to seed all periodic syncs
208+ private int mSyncRandomOffsetMillis ;
209+
207210 private static final long SYNC_ALARM_TIMEOUT_MIN = 30 * 1000 ; // 30 seconds
208211 private static final long SYNC_ALARM_TIMEOUT_MAX = 2 * 60 * 60 * 1000 ; // two hours
209212
@@ -472,6 +475,9 @@ public void onStatusChanged(int which) {
472475 // do this synchronously to ensure we have the accounts before this call returns
473476 onAccountsUpdated (null );
474477 }
478+
479+ // Pick a random second in a day to seed all periodic syncs
480+ mSyncRandomOffsetMillis = mSyncStorageEngine .getSyncRandomOffset () * 1000 ;
475481 }
476482
477483 /**
@@ -700,6 +706,7 @@ private void sendSyncAlarmMessage() {
700706
701707 private void sendCheckAlarmsMessage () {
702708 if (Log .isLoggable (TAG , Log .VERBOSE )) Log .v (TAG , "sending MESSAGE_CHECK_ALARMS" );
709+ mSyncHandler .removeMessages (SyncHandler .MESSAGE_CHECK_ALARMS );
703710 mSyncHandler .sendEmptyMessage (SyncHandler .MESSAGE_CHECK_ALARMS );
704711 }
705712
@@ -748,6 +755,8 @@ private void clearBackoffSetting(SyncOperation op) {
748755 }
749756
750757 private void increaseBackoffSetting (SyncOperation op ) {
758+ // TODO: Use this function to align it to an already scheduled sync
759+ // operation in the specified window
751760 final long now = SystemClock .elapsedRealtime ();
752761
753762 final Pair <Long , Long > previousSettings =
@@ -1094,6 +1103,8 @@ protected void dumpSyncState(PrintWriter pw) {
10941103 final long now = SystemClock .elapsedRealtime ();
10951104 pw .print ("now: " ); pw .print (now );
10961105 pw .println (" (" + formatTime (System .currentTimeMillis ()) + ")" );
1106+ pw .print ("offset: " ); pw .print (DateUtils .formatElapsedTime (mSyncRandomOffsetMillis /1000 ));
1107+ pw .println (" (HH:MM:SS)" );
10971108 pw .print ("uptime: " ); pw .print (DateUtils .formatElapsedTime (now /1000 ));
10981109 pw .println (" (HH:MM:SS)" );
10991110 pw .print ("time spent syncing: " );
@@ -1805,6 +1816,9 @@ private long scheduleReadyPeriodicSyncs() {
18051816 AccountAndUser [] accounts = mAccounts ;
18061817
18071818 final long nowAbsolute = System .currentTimeMillis ();
1819+ final long shiftedNowAbsolute = (0 < nowAbsolute - mSyncRandomOffsetMillis )
1820+ ? (nowAbsolute - mSyncRandomOffsetMillis ) : 0 ;
1821+
18081822 ArrayList <SyncStorageEngine .AuthorityInfo > infos = mSyncStorageEngine .getAuthorities ();
18091823 for (SyncStorageEngine .AuthorityInfo info : infos ) {
18101824 // skip the sync if the account of this operation no longer exists
@@ -1826,16 +1840,32 @@ private long scheduleReadyPeriodicSyncs() {
18261840 SyncStatusInfo status = mSyncStorageEngine .getOrCreateSyncStatus (info );
18271841 for (int i = 0 , N = info .periodicSyncs .size (); i < N ; i ++) {
18281842 final Bundle extras = info .periodicSyncs .get (i ).first ;
1829- final Long periodInSeconds = info .periodicSyncs .get (i ).second ;
1843+ final Long periodInMillis = info .periodicSyncs .get (i ).second * 1000 ;
18301844 // find when this periodic sync was last scheduled to run
18311845 final long lastPollTimeAbsolute = status .getPeriodicSyncTime (i );
1832- // compute when this periodic sync should next run - this can be in the future
1833- // for example if the user changed the time, synced and changed back.
1834- final long nextPollTimeAbsolute = lastPollTimeAbsolute > nowAbsolute
1835- ? nowAbsolute
1836- : lastPollTimeAbsolute + periodInSeconds * 1000 ;
1837- // if it is ready to run then schedule it and mark it as having been scheduled
1838- if (nextPollTimeAbsolute <= nowAbsolute ) {
1846+
1847+ long remainingMillis
1848+ = periodInMillis - (shiftedNowAbsolute % periodInMillis );
1849+
1850+ /*
1851+ * Sync scheduling strategy:
1852+ * Set the next periodic sync based on a random offset (in seconds).
1853+ *
1854+ * Also sync right now if any of the following cases hold
1855+ * and mark it as having been scheduled
1856+ *
1857+ * Case 1: This sync is ready to run now.
1858+ * Case 2: If the lastPollTimeAbsolute is in the future,
1859+ * sync now and reinitialize. This can happen for
1860+ * example if the user changed the time, synced and
1861+ * changed back.
1862+ * Case 3: If we failed to sync at the last scheduled time
1863+ */
1864+ if (remainingMillis == periodInMillis // Case 1
1865+ || lastPollTimeAbsolute > nowAbsolute // Case 2
1866+ || (nowAbsolute - lastPollTimeAbsolute
1867+ >= periodInMillis )) { // Case 3
1868+ // Sync now
18391869 final Pair <Long , Long > backoff = mSyncStorageEngine .getBackoff (
18401870 info .account , info .userId , info .authority );
18411871 final RegisteredServicesCache .ServiceInfo <SyncAdapterType > syncAdapterInfo =
@@ -1853,12 +1883,13 @@ private long scheduleReadyPeriodicSyncs() {
18531883 info .account , info .userId , info .authority ),
18541884 syncAdapterInfo .type .allowParallelSyncs ()));
18551885 status .setPeriodicSyncTime (i , nowAbsolute );
1856- } else {
1857- // it isn't ready to run, remember this time if it is earlier than
1858- // earliestFuturePollTime
1859- if (nextPollTimeAbsolute < earliestFuturePollTime ) {
1860- earliestFuturePollTime = nextPollTimeAbsolute ;
1861- }
1886+ }
1887+ // Compute when this periodic sync should next run
1888+ final long nextPollTimeAbsolute = nowAbsolute + remainingMillis ;
1889+
1890+ // remember this time if it is earlier than earliestFuturePollTime
1891+ if (nextPollTimeAbsolute < earliestFuturePollTime ) {
1892+ earliestFuturePollTime = nextPollTimeAbsolute ;
18621893 }
18631894 }
18641895 }
0 commit comments