From 2c49e9087ade806fa837e6939f4de33f9fbf4820 Mon Sep 17 00:00:00 2001 From: Grisha Kruglov Date: Tue, 8 Nov 2016 12:38:00 -0800 Subject: [PATCH] Bug 1291821 - Keep track of sync deadline r=rnewman MozReview-Commit-ID: Fvuc05K1arV --HG-- extra : rebase_source : 74b0d4dc58c0cd2c1113253eee28ba783e114803 --- .../gecko/fxa/sync/FxAccountSyncAdapter.java | 22 ++++++++++++++----- .../org/mozilla/gecko/sync/GlobalSession.java | 15 +++++++++++-- 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/fxa/sync/FxAccountSyncAdapter.java b/mobile/android/services/src/main/java/org/mozilla/gecko/fxa/sync/FxAccountSyncAdapter.java index 30990cf7fb44..f4fcc3e312bc 100644 --- a/mobile/android/services/src/main/java/org/mozilla/gecko/fxa/sync/FxAccountSyncAdapter.java +++ b/mobile/android/services/src/main/java/org/mozilla/gecko/fxa/sync/FxAccountSyncAdapter.java @@ -60,6 +60,7 @@ import java.util.concurrent.BlockingQueue; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; public class FxAccountSyncAdapter extends AbstractThreadedSyncAdapter { private static final String LOG_TAG = FxAccountSyncAdapter.class.getSimpleName(); @@ -74,6 +75,11 @@ public class FxAccountSyncAdapter extends AbstractThreadedSyncAdapter { private static final int MINIMUM_SYNC_DELAY_MILLIS = 15 * 1000; // 15 seconds. private volatile long lastSyncRealtimeMillis; + // Non-user initiated sync can't take longer than 30 minutes. + // To ensure we're not churning through device's battery/resources, we limit sync to 10 minutes, + // and request a re-sync if we hit that deadline. + private static final long SYNC_DEADLINE_DELTA_MILLIS = TimeUnit.MINUTES.toMillis(10); + protected final ExecutorService executor; protected final FxAccountNotificationManager notificationManager; @@ -231,8 +237,7 @@ public class FxAccountSyncAdapter extends AbstractThreadedSyncAdapter { return forced; } - protected void syncWithAssertion(final String audience, - final String assertion, + protected void syncWithAssertion(final String assertion, final URI tokenServerEndpointURI, final BackoffHandler tokenBackoffHandler, final SharedPreferences sharedPrefs, @@ -240,7 +245,8 @@ public class FxAccountSyncAdapter extends AbstractThreadedSyncAdapter { final String clientState, final SessionCallback callback, final Bundle extras, - final AndroidFxAccount fxAccount) { + final AndroidFxAccount fxAccount, + final long syncDeadline) { final TokenServerClientDelegate delegate = new TokenServerClientDelegate() { private boolean didReceiveBackoff = false; @@ -321,7 +327,7 @@ public class FxAccountSyncAdapter extends AbstractThreadedSyncAdapter { syncConfig.setClusterURL(storageServerURI); globalSession = new GlobalSession(syncConfig, callback, context, clientsDataDelegate); - globalSession.start(); + globalSession.start(syncDeadline); } catch (Exception e) { callback.handleError(globalSession, e); return; @@ -386,6 +392,10 @@ public class FxAccountSyncAdapter extends AbstractThreadedSyncAdapter { final Context context = getContext(); final AndroidFxAccount fxAccount = new AndroidFxAccount(context, account); + // NB: we use elapsedRealtime which is time since boot, to ensure our clock is monotonic and isn't + // paused while CPU is in the power-saving mode. + final long syncDeadline = SystemClock.elapsedRealtime() + SYNC_DEADLINE_DELTA_MILLIS; + Logger.info(LOG_TAG, "Syncing FxAccount" + " account named like " + Utils.obfuscateEmail(account.name) + " for authority " + authority + @@ -536,7 +546,9 @@ public class FxAccountSyncAdapter extends AbstractThreadedSyncAdapter { final SessionCallback sessionCallback = new SessionCallback(syncDelegate, schedulePolicy); final KeyBundle syncKeyBundle = married.getSyncKeyBundle(); final String clientState = married.getClientState(); - syncWithAssertion(audience, assertion, tokenServerEndpointURI, tokenBackoffHandler, sharedPrefs, syncKeyBundle, clientState, sessionCallback, extras, fxAccount); + syncWithAssertion( + assertion, tokenServerEndpointURI, tokenBackoffHandler, sharedPrefs, + syncKeyBundle, clientState, sessionCallback, extras, fxAccount, syncDeadline); // Register the device if necessary (asynchronous, in another thread) if (fxAccount.getDeviceRegistrationVersion() != FxAccountDeviceRegistrator.DEVICE_REGISTRATION_VERSION diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/GlobalSession.java b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/GlobalSession.java index e28bbe4cca95..8ddb87351fa3 100644 --- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/GlobalSession.java +++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/GlobalSession.java @@ -74,6 +74,8 @@ public class GlobalSession implements HttpResponseObserver { protected final Context context; protected final ClientsDataDelegate clientsDelegate; + private long syncDeadline; + /** * Map from engine name to new settings for an updated meta/global record. * Engines to remove will have null EngineSettings. @@ -234,6 +236,10 @@ public class GlobalSession implements HttpResponseObserver { return out; } + public long getSyncDeadline() { + return syncDeadline; + } + /** * Advance and loop around the stages of a sync. * @param current @@ -293,10 +299,14 @@ public class GlobalSession implements HttpResponseObserver { * * @throws AlreadySyncingException */ - public void start() throws AlreadySyncingException { + public void start(final long syncDeadline) throws AlreadySyncingException { if (this.currentState != GlobalSyncStage.Stage.idle) { throw new AlreadySyncingException(this.currentState); } + + // Make the deadline value available to stages via its getter. + this.syncDeadline = syncDeadline; + installAsHttpResponseObserver(); // Uninstalled by completeSync or abort. this.advance(); } @@ -311,7 +321,8 @@ public class GlobalSession implements HttpResponseObserver { this.callback.handleAborted(this, "Told to back off."); return; } - this.start(); + // Restart with the same deadline as before. + this.start(syncDeadline); } /**