summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYu Ping Hu <yph@google.com>2014-03-17 14:48:44 -0700
committerYu Ping Hu <yph@google.com>2014-03-17 18:03:20 -0700
commitaac54f00981e2eb22d22b6886e4c033948f31a0b (patch)
treeaaea3d9b70effa8723cfd6af27e6eb4c975a8d9e
parent51ce7c7fe90d559131645f931926f1b08540b108 (diff)
downloadExchange-aac54f00981e2eb22d22b6886e4c033948f31a0b.tar.gz
If Ping encounters an error, wait before repinging.
This is a short-term fix; we should implement smarter backoff behavior later. However, let's fix the battery burn immediately. This CL also includes a fix to re-pinging in the error case for people who do not have mail sync enabled. Bug: 12589402 Bug: 13227663 Change-Id: If61d4a42fe846d8f4b5c16e84d6196ad61ddbe0e
-rw-r--r--src/com/android/exchange/eas/EasPing.java10
-rw-r--r--src/com/android/exchange/service/EmailSyncAdapterService.java64
2 files changed, 49 insertions, 25 deletions
diff --git a/src/com/android/exchange/eas/EasPing.java b/src/com/android/exchange/eas/EasPing.java
index be1a679a..2ca44200 100644
--- a/src/com/android/exchange/eas/EasPing.java
+++ b/src/com/android/exchange/eas/EasPing.java
@@ -412,9 +412,17 @@ public class EasPing extends EasOperation {
mAmAccount.toString(), extras.toString());
}
+ /**
+ * Request a ping-only sync via the SyncManager. This is used in error paths, which is also why
+ * we don't just create and start a new ping task immediately: in the case where we have loss
+ * of network, we want to take advantage of the SyncManager to schedule this when we expect it
+ * to be able to work.
+ * @param amAccount Account that needs to ping.
+ */
public static void requestPing(final android.accounts.Account amAccount) {
- final Bundle extras = new Bundle(1);
+ final Bundle extras = new Bundle(2);
extras.putBoolean(Mailbox.SYNC_EXTRA_PUSH_ONLY, true);
+ extras.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
ContentResolver.requestSync(amAccount, EmailContent.AUTHORITY, extras);
LogUtils.i(LOG_TAG, "requestPing EasOperation %s, %s",
amAccount.toString(), extras.toString());
diff --git a/src/com/android/exchange/service/EmailSyncAdapterService.java b/src/com/android/exchange/service/EmailSyncAdapterService.java
index d963ec31..b378cd9e 100644
--- a/src/com/android/exchange/service/EmailSyncAdapterService.java
+++ b/src/com/android/exchange/service/EmailSyncAdapterService.java
@@ -273,27 +273,16 @@ public class EmailSyncAdapterService extends AbstractSyncAdapterService {
if (pingSyncHandler != null) {
pingSyncHandler.restart();
} else {
- // Start a new ping.
- // Note: unlike startSync, we CANNOT allow the caller to do the actual work.
- // If we return before the ping starts, there's a race condition where another
- // ping or sync might start first. It only works for startSync because sync is
- // higher priority than ping (i.e. a ping can't start while a sync is pending)
- // and only one sync can run at a time.
if (lastSyncHadError) {
// Schedule an alarm to set up the ping in 5 minutes
- final Intent intent = new Intent(service, EmailSyncAdapterService.class);
- intent.setAction(Eas.EXCHANGE_SERVICE_INTENT_ACTION);
- intent.putExtra(EXTRA_START_PING, true);
- intent.putExtra(EXTRA_PING_ACCOUNT, amAccount);
- final PendingIntent pi = PendingIntent.getService(
- EmailSyncAdapterService.this, 0, intent,
- PendingIntent.FLAG_ONE_SHOT);
- final AlarmManager am = (AlarmManager)getSystemService(
- Context.ALARM_SERVICE);
- final long atTime = SystemClock.elapsedRealtime() +
- SYNC_ERROR_BACKOFF_MILLIS;
- am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, atTime, pi);
+ scheduleDelayedPing(amAccount, SYNC_ERROR_BACKOFF_MILLIS);
} else {
+ // Start a new ping.
+ // Note: unlike startSync, we CANNOT allow the caller to do the actual work.
+ // If we return before the ping starts, there's a race condition where
+ // another ping or sync might start first. It only works for startSync
+ // because sync is higher priority than ping (i.e. a ping can't start while
+ // a sync is pending) and only one sync can run at a time.
final PingTask pingHandler = new PingTask(service, account, amAccount,
this);
mPingHandlers.put(account.mId, pingHandler);
@@ -351,14 +340,19 @@ public class EmailSyncAdapterService extends AbstractSyncAdapterService {
// TODO: if (pingStatus == PingParser.STATUS_FAILED), notify UI.
// TODO: if (pingStatus == PingParser.STATUS_REQUEST_TOO_MANY_FOLDERS), notify UI.
- // TODO: Should this just re-request ping if status < 0? This would do the wrong thing
- // for e.g. auth errors, though.
if (pingStatus == EasOperation.RESULT_REQUEST_FAILURE ||
pingStatus == EasOperation.RESULT_OTHER_FAILURE) {
- // Request a new ping through the SyncManager. This will do the right thing if the
- // exception was due to loss of network connectivity, etc. (i.e. it will wait for
- // network to restore and then request it).
- EasPing.requestPing(amAccount);
+ // TODO: Sticky problem here: we necessarily aren't in a sync, so it's impossible to
+ // signal the error to the SyncManager and take advantage of backoff there. Worse,
+ // the current mechanism for how we do this will just encourage spammy requests
+ // since the actual ping-only sync request ALWAYS succeeds.
+ // So for now, let's delay a bit before asking the SyncManager to perform the sync.
+ // Longer term, this should be incorporated into some form of backoff, either
+ // by integrating with the SyncManager more fully or by implementing a Ping-specific
+ // backoff mechanism (e.g. integrate this with the logic for ping duration).
+ LogUtils.e(TAG, "Ping for account %d completed with error %d, delaying next ping",
+ accountId, pingStatus);
+ scheduleDelayedPing(amAccount, SYNC_ERROR_BACKOFF_MILLIS);
} else {
stopServiceIfNoPings();
}
@@ -978,4 +972,26 @@ public class EmailSyncAdapterService extends AbstractSyncAdapterService {
}
return authsToSync;
}
+
+ /**
+ * Schedule to have a ping start some time in the future. This is used when we encounter an
+ * error, and properly should be a more full featured back-off, but for the short run, just
+ * waiting a few minutes at least avoids burning battery.
+ * @param amAccount The account that needs to be pinged.
+ * @param delay The time in milliseconds to wait before requesting the ping-only sync. Note that
+ * it may take longer than this before the ping actually happens, since there's two
+ * layers of waiting ({@link AlarmManager} can choose to wait longer, as can the
+ * SyncManager).
+ */
+ private void scheduleDelayedPing(final android.accounts.Account amAccount, final long delay) {
+ final Intent intent = new Intent(this, EmailSyncAdapterService.class);
+ intent.setAction(Eas.EXCHANGE_SERVICE_INTENT_ACTION);
+ intent.putExtra(EXTRA_START_PING, true);
+ intent.putExtra(EXTRA_PING_ACCOUNT, amAccount);
+ final PendingIntent pi = PendingIntent.getService(this, 0, intent,
+ PendingIntent.FLAG_ONE_SHOT);
+ final AlarmManager am = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
+ final long atTime = SystemClock.elapsedRealtime() + delay;
+ am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, atTime, pi);
+ }
}