diff options
author | Yu Ping Hu <yph@google.com> | 2014-03-17 14:48:44 -0700 |
---|---|---|
committer | Yu Ping Hu <yph@google.com> | 2014-03-17 18:03:20 -0700 |
commit | aac54f00981e2eb22d22b6886e4c033948f31a0b (patch) | |
tree | aaea3d9b70effa8723cfd6af27e6eb4c975a8d9e | |
parent | 51ce7c7fe90d559131645f931926f1b08540b108 (diff) | |
download | Exchange-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.java | 10 | ||||
-rw-r--r-- | src/com/android/exchange/service/EmailSyncAdapterService.java | 64 |
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); + } } |