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

Commit 9766937b authored by Ashish Sharma's avatar Ashish Sharma Committed by Android (Google) Code Review
Browse files

Merge "Synchronize/align periodic sync alarms based on a random per device seed value."

parents f1352d87 69d95de5
Loading
Loading
Loading
Loading
+45 −14
Original line number Diff line number Diff line
@@ -205,6 +205,9 @@ public class SyncManager implements OnAccountsUpdateListener {

    private final PowerManager mPowerManager;

    // Use this as a random offset to seed all periodic syncs
    private int mSyncRandomOffsetMillis;

    private static final long SYNC_ALARM_TIMEOUT_MIN = 30 * 1000; // 30 seconds
    private static final long SYNC_ALARM_TIMEOUT_MAX = 2 * 60 * 60 * 1000; // two hours

@@ -438,6 +441,9 @@ public class SyncManager implements OnAccountsUpdateListener {
            // do this synchronously to ensure we have the accounts before this call returns
            onAccountsUpdated(null);
        }

        // Pick a random second in a day to seed all periodic syncs
        mSyncRandomOffsetMillis = mSyncStorageEngine.getSyncRandomOffset() * 1000;
    }

    /**
@@ -666,6 +672,7 @@ public class SyncManager implements OnAccountsUpdateListener {

    private void sendCheckAlarmsMessage() {
        if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "sending MESSAGE_CHECK_ALARMS");
        mSyncHandler.removeMessages(SyncHandler.MESSAGE_CHECK_ALARMS);
        mSyncHandler.sendEmptyMessage(SyncHandler.MESSAGE_CHECK_ALARMS);
    }

@@ -714,6 +721,8 @@ public class SyncManager implements OnAccountsUpdateListener {
    }

    private void increaseBackoffSetting(SyncOperation op) {
        // TODO: Use this function to align it to an already scheduled sync
        //       operation in the specified window
        final long now = SystemClock.elapsedRealtime();

        final Pair<Long, Long> previousSettings =
@@ -1060,6 +1069,8 @@ public class SyncManager implements OnAccountsUpdateListener {
        final long now = SystemClock.elapsedRealtime();
        pw.print("now: "); pw.print(now);
        pw.println(" (" + formatTime(System.currentTimeMillis()) + ")");
        pw.print("offset: "); pw.print(DateUtils.formatElapsedTime(mSyncRandomOffsetMillis/1000));
        pw.println(" (HH:MM:SS)");
        pw.print("uptime: "); pw.print(DateUtils.formatElapsedTime(now/1000));
                pw.println(" (HH:MM:SS)");
        pw.print("time spent syncing: ");
@@ -1771,6 +1782,9 @@ public class SyncManager implements OnAccountsUpdateListener {
            AccountAndUser[] accounts = mAccounts;

            final long nowAbsolute = System.currentTimeMillis();
            final long shiftedNowAbsolute = (0 < nowAbsolute - mSyncRandomOffsetMillis)
                                               ? (nowAbsolute  - mSyncRandomOffsetMillis) : 0;

            ArrayList<SyncStorageEngine.AuthorityInfo> infos = mSyncStorageEngine.getAuthorities();
            for (SyncStorageEngine.AuthorityInfo info : infos) {
                // skip the sync if the account of this operation no longer exists
@@ -1792,16 +1806,32 @@ public class SyncManager implements OnAccountsUpdateListener {
                SyncStatusInfo status = mSyncStorageEngine.getOrCreateSyncStatus(info);
                for (int i = 0, N = info.periodicSyncs.size(); i < N; i++) {
                    final Bundle extras = info.periodicSyncs.get(i).first;
                    final Long periodInSeconds = info.periodicSyncs.get(i).second;
                    final Long periodInMillis = info.periodicSyncs.get(i).second * 1000;
                    // find when this periodic sync was last scheduled to run
                    final long lastPollTimeAbsolute = status.getPeriodicSyncTime(i);
                    // compute when this periodic sync should next run - this can be in the future
                    // for example if the user changed the time, synced and changed back.
                    final long nextPollTimeAbsolute = lastPollTimeAbsolute > nowAbsolute
                            ? nowAbsolute
                            : lastPollTimeAbsolute + periodInSeconds * 1000;
                    // if it is ready to run then schedule it and mark it as having been scheduled
                    if (nextPollTimeAbsolute <= nowAbsolute) {

                    long remainingMillis
                            = periodInMillis - (shiftedNowAbsolute % periodInMillis);

                    /*
                     * Sync scheduling strategy:
                     *    Set the next periodic sync based on a random offset (in seconds).
                     *
                     *    Also sync right now if any of the following cases hold
                     *    and mark it as having been scheduled
                     *
                     * Case 1:  This sync is ready to run now.
                     * Case 2:  If the lastPollTimeAbsolute is in the future,
                     *          sync now and reinitialize. This can happen for
                     *          example if the user changed the time, synced and
                     *          changed back.
                     * Case 3:  If we failed to sync at the last scheduled time
                     */
                    if (remainingMillis == periodInMillis  // Case 1
                            || lastPollTimeAbsolute > nowAbsolute // Case 2
                            || (nowAbsolute - lastPollTimeAbsolute
                                    >= periodInMillis)) { // Case 3
                        // Sync now
                        final Pair<Long, Long> backoff = mSyncStorageEngine.getBackoff(
                                info.account, info.userId, info.authority);
                        final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo =
@@ -1819,15 +1849,16 @@ public class SyncManager implements OnAccountsUpdateListener {
                                                info.account, info.userId, info.authority),
                                        syncAdapterInfo.type.allowParallelSyncs()));
                        status.setPeriodicSyncTime(i, nowAbsolute);
                    } else {
                        // it isn't ready to run, remember this time if it is earlier than
                        // earliestFuturePollTime
                    }
                    // Compute when this periodic sync should next run
                    final long nextPollTimeAbsolute = nowAbsolute + remainingMillis;

                    // remember this time if it is earlier than earliestFuturePollTime
                    if (nextPollTimeAbsolute < earliestFuturePollTime) {
                        earliestFuturePollTime = nextPollTimeAbsolute;
                    }
                }
            }
            }

            if (earliestFuturePollTime == Long.MAX_VALUE) {
                return Long.MAX_VALUE;
+20 −0
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@ import android.os.Message;
import android.os.Parcel;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.SystemClock;
import android.util.Log;
import android.util.SparseArray;
import android.util.Xml;
@@ -49,6 +50,7 @@ import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Random;
import java.util.TimeZone;
import java.util.List;

@@ -65,6 +67,7 @@ public class SyncStorageEngine extends Handler {

    private static final String XML_ATTR_NEXT_AUTHORITY_ID = "nextAuthorityId";
    private static final String XML_ATTR_LISTEN_FOR_TICKLES = "listen-for-tickles";
    private static final String XML_ATTR_SYNC_RANDOM_OFFSET = "offsetInSeconds";
    private static final String XML_ATTR_ENABLED = "enabled";
    private static final String XML_ATTR_USER = "user";
    private static final String XML_TAG_LISTEN_FOR_TICKLES = "listenForTickles";
@@ -277,6 +280,8 @@ public class SyncStorageEngine extends Handler {

    private static volatile SyncStorageEngine sSyncStorageEngine = null;

    private int mSyncRandomOffset;

    /**
     * This file contains the core engine state: all accounts and the
     * settings for them.  It must never be lost, and should be changed
@@ -375,6 +380,10 @@ public class SyncStorageEngine extends Handler {
        }
    }

    public int getSyncRandomOffset() {
        return mSyncRandomOffset;
    }

    public void addStatusChangeListener(int mask, ISyncStatusObserver callback) {
        synchronized (mAuthorities) {
            mChangeListeners.register(callback, mask);
@@ -1465,6 +1474,16 @@ public class SyncStorageEngine extends Handler {
                } catch (NumberFormatException e) {
                    // don't care
                }
                String offsetString = parser.getAttributeValue(null, XML_ATTR_SYNC_RANDOM_OFFSET);
                try {
                    mSyncRandomOffset = (offsetString == null) ? 0 : Integer.parseInt(offsetString);
                } catch (NumberFormatException e) {
                    mSyncRandomOffset = 0;
                }
                if (mSyncRandomOffset == 0) {
                    Random random = new Random(System.currentTimeMillis());
                    mSyncRandomOffset = random.nextInt(86400);
                }
                mMasterSyncAutomatically.put(0, listen == null || Boolean.parseBoolean(listen));
                eventType = parser.next();
                AuthorityInfo authority = null;
@@ -1705,6 +1724,7 @@ public class SyncStorageEngine extends Handler {
            out.startTag(null, "accounts");
            out.attribute(null, "version", Integer.toString(ACCOUNTS_VERSION));
            out.attribute(null, XML_ATTR_NEXT_AUTHORITY_ID, Integer.toString(mNextAuthorityId));
            out.attribute(null, XML_ATTR_SYNC_RANDOM_OFFSET, Integer.toString(mSyncRandomOffset));

            // Write the Sync Automatically flags for each user
            final int M = mMasterSyncAutomatically.size();