mobile/android/base/fxa/sync/FxAccountSchedulePolicy.java

Wed, 31 Dec 2014 07:22:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:22:50 +0100
branch
TOR_BUG_3246
changeset 4
fc2d59ddac77
permissions
-rw-r--r--

Correct previous dual key logic pending first delivery installment.

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 package org.mozilla.gecko.fxa.sync;
michael@0 6
michael@0 7 import org.mozilla.gecko.background.common.log.Logger;
michael@0 8 import org.mozilla.gecko.db.BrowserContract;
michael@0 9 import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
michael@0 10 import org.mozilla.gecko.fxa.login.State.Action;
michael@0 11 import org.mozilla.gecko.sync.BackoffHandler;
michael@0 12
michael@0 13 import android.accounts.Account;
michael@0 14 import android.content.ContentResolver;
michael@0 15 import android.content.Context;
michael@0 16 import android.os.Bundle;
michael@0 17
michael@0 18 public class FxAccountSchedulePolicy implements SchedulePolicy {
michael@0 19 private static final String LOG_TAG = "FxAccountSchedulePolicy";
michael@0 20
michael@0 21 // Our poll intervals are used to trigger automatic background syncs
michael@0 22 // in the absence of user activity.
michael@0 23 //
michael@0 24 // We also receive sync requests as a result of network tickles, so
michael@0 25 // these intervals are long, with the exception of the rapid polling
michael@0 26 // while we wait for verification: if we're waiting for the user to
michael@0 27 // click on a verification link, we sync very often in order to detect
michael@0 28 // a change in state.
michael@0 29 //
michael@0 30 // In the case of unverified -> unverified (no transition), this should be
michael@0 31 // very close to a single HTTP request (with the SyncAdapter overhead, of
michael@0 32 // course, but that's not wildly different from alarm manager overhead).
michael@0 33 //
michael@0 34 // The /account/status endpoint is HAWK authed by sessionToken, so we still
michael@0 35 // have to do some crypto no matter what.
michael@0 36
michael@0 37 // TODO: only do this for a while...
michael@0 38 public static final long POLL_INTERVAL_PENDING_VERIFICATION = 60; // 1 minute.
michael@0 39
michael@0 40 // If we're in some kind of error state, there's no point trying often.
michael@0 41 // This is not the same as a server-imposed backoff, which will be
michael@0 42 // reflected dynamically.
michael@0 43 public static final long POLL_INTERVAL_ERROR_STATE_SEC = 24 * 60 * 60; // 24 hours.
michael@0 44
michael@0 45 // If we're the only device, just sync once or twice a day in case that
michael@0 46 // changes.
michael@0 47 public static final long POLL_INTERVAL_SINGLE_DEVICE_SEC = 18 * 60 * 60; // 18 hours.
michael@0 48
michael@0 49 // And if we know there are other devices, let's sync often enough that
michael@0 50 // we'll be more likely to be caught up (even if not completely) by the
michael@0 51 // time you next use this device. This is also achieved via Android's
michael@0 52 // network tickles.
michael@0 53 public static final long POLL_INTERVAL_MULTI_DEVICE_SEC = 12 * 60 * 60; // 12 hours.
michael@0 54
michael@0 55 // This is used solely as an optimization for backoff handling, so it's not
michael@0 56 // persisted.
michael@0 57 private static volatile long POLL_INTERVAL_CURRENT_SEC = POLL_INTERVAL_SINGLE_DEVICE_SEC;
michael@0 58
michael@0 59 // Never sync more frequently than this, unless forced.
michael@0 60 // This is to avoid overly-frequent syncs during active browsing.
michael@0 61 public static final long RATE_LIMIT_FUNDAMENTAL_SEC = 90; // 90 seconds.
michael@0 62
michael@0 63 /**
michael@0 64 * We are prompted to sync by several inputs:
michael@0 65 * * Periodic syncs that we schedule at long intervals. See the POLL constants.
michael@0 66 * * Network-tickle-based syncs that Android starts.
michael@0 67 * * Upload-only syncs that are caused by local database writes.
michael@0 68 *
michael@0 69 * We rate-limit periodic and network-sourced events with this constant.
michael@0 70 * We rate limit <b>both</b> with {@link FxAccountSchedulePolicy#RATE_LIMIT_FUNDAMENTAL_SEC}.
michael@0 71 */
michael@0 72 public static final long RATE_LIMIT_BACKGROUND_SEC = 60 * 60; // 1 hour.
michael@0 73
michael@0 74 private final AndroidFxAccount account;
michael@0 75 private final Context context;
michael@0 76
michael@0 77 public FxAccountSchedulePolicy(Context context, AndroidFxAccount account) {
michael@0 78 this.account = account;
michael@0 79 this.context = context;
michael@0 80 }
michael@0 81
michael@0 82 /**
michael@0 83 * Return a millisecond timestamp in the future, offset from the current
michael@0 84 * time by the provided amount.
michael@0 85 * @param millis the duration by which to delay
michael@0 86 * @return a timestamp.
michael@0 87 */
michael@0 88 private static long delay(long millis) {
michael@0 89 return System.currentTimeMillis() + millis;
michael@0 90 }
michael@0 91
michael@0 92 /**
michael@0 93 * Updates the existing system periodic sync interval to the specified duration.
michael@0 94 *
michael@0 95 * @param intervalSeconds the requested period, which Android will vary by up to 4%.
michael@0 96 */
michael@0 97 protected void requestPeriodicSync(final long intervalSeconds) {
michael@0 98 final String authority = BrowserContract.AUTHORITY;
michael@0 99 final Account account = this.account.getAndroidAccount();
michael@0 100 this.context.getContentResolver();
michael@0 101 Logger.info(LOG_TAG, "Scheduling periodic sync for " + intervalSeconds + ".");
michael@0 102 ContentResolver.addPeriodicSync(account, authority, Bundle.EMPTY, intervalSeconds);
michael@0 103 POLL_INTERVAL_CURRENT_SEC = intervalSeconds;
michael@0 104 }
michael@0 105
michael@0 106 @Override
michael@0 107 public void onSuccessfulSync(int otherClientsCount) {
michael@0 108 // This undoes the change made in observeBackoffMillis -- once we hit backoff we'll
michael@0 109 // periodically sync at the backoff duration, but as soon as we succeed we'll switch
michael@0 110 // into the client-count-dependent interval.
michael@0 111 long interval = (otherClientsCount > 0) ? POLL_INTERVAL_MULTI_DEVICE_SEC : POLL_INTERVAL_SINGLE_DEVICE_SEC;
michael@0 112 requestPeriodicSync(interval);
michael@0 113 }
michael@0 114
michael@0 115 @Override
michael@0 116 public void onHandleFinal(Action needed) {
michael@0 117 switch (needed) {
michael@0 118 case NeedsPassword:
michael@0 119 case NeedsUpgrade:
michael@0 120 requestPeriodicSync(POLL_INTERVAL_ERROR_STATE_SEC);
michael@0 121 break;
michael@0 122 case NeedsVerification:
michael@0 123 requestPeriodicSync(POLL_INTERVAL_PENDING_VERIFICATION);
michael@0 124 break;
michael@0 125 case None:
michael@0 126 // No action needed: we'll set the periodic sync interval
michael@0 127 // when the sync finishes, via the SessionCallback.
michael@0 128 break;
michael@0 129 }
michael@0 130 }
michael@0 131
michael@0 132 @Override
michael@0 133 public void onUpgradeRequired() {
michael@0 134 // TODO: this shouldn't occur in FxA, but when we upgrade we
michael@0 135 // need to reduce the interval again.
michael@0 136 requestPeriodicSync(POLL_INTERVAL_ERROR_STATE_SEC);
michael@0 137 }
michael@0 138
michael@0 139 @Override
michael@0 140 public void onUnauthorized() {
michael@0 141 // TODO: this shouldn't occur in FxA, but when we fix our credentials
michael@0 142 // we need to reduce the interval again.
michael@0 143 requestPeriodicSync(POLL_INTERVAL_ERROR_STATE_SEC);
michael@0 144 }
michael@0 145
michael@0 146 @Override
michael@0 147 public void configureBackoffMillisOnBackoff(BackoffHandler backoffHandler, long backoffMillis, boolean onlyExtend) {
michael@0 148 if (onlyExtend) {
michael@0 149 backoffHandler.extendEarliestNextRequest(delay(backoffMillis));
michael@0 150 } else {
michael@0 151 backoffHandler.setEarliestNextRequest(delay(backoffMillis));
michael@0 152 }
michael@0 153
michael@0 154 // Yes, we might be part-way through the interval, in which case the backoff
michael@0 155 // code will do its job. But we certainly don't want to reduce the interval
michael@0 156 // if we're given a small backoff instruction.
michael@0 157 // We'll reset the poll interval next time we sync without a backoff instruction.
michael@0 158 if (backoffMillis > (POLL_INTERVAL_CURRENT_SEC * 1000)) {
michael@0 159 // Slightly inflate the backoff duration to ensure that a fuzzed
michael@0 160 // periodic sync doesn't occur before our backoff has passed. Android
michael@0 161 // 19+ default to a 4% fuzz factor.
michael@0 162 requestPeriodicSync((long) Math.ceil((1.05 * backoffMillis) / 1000));
michael@0 163 }
michael@0 164 }
michael@0 165
michael@0 166 /**
michael@0 167 * Accepts two {@link BackoffHandler} instances as input. These are used
michael@0 168 * respectively to track fundamental rate limiting, and to separately
michael@0 169 * rate-limit periodic and network-tickled syncs.
michael@0 170 */
michael@0 171 @Override
michael@0 172 public void configureBackoffMillisBeforeSyncing(BackoffHandler fundamentalRateHandler, BackoffHandler backgroundRateHandler) {
michael@0 173 fundamentalRateHandler.setEarliestNextRequest(delay(RATE_LIMIT_FUNDAMENTAL_SEC * 1000));
michael@0 174 backgroundRateHandler.setEarliestNextRequest(delay(RATE_LIMIT_BACKGROUND_SEC * 1000));
michael@0 175 }
michael@0 176 }

mercurial