diff options
author | Yu Ping Hu <yph@google.com> | 2013-11-15 13:43:03 -0800 |
---|---|---|
committer | Android Git Automerger <android-git-automerger@android.com> | 2013-11-15 13:43:03 -0800 |
commit | 4f0b3ce2f4a913bc24870e7c331b0fdff5c6f1ca (patch) | |
tree | 4fd2b241bb3987cfc002843e7dc264b8a0640723 | |
parent | 27e2eac60a113ef89f0603d6a2da9884385810b7 (diff) | |
parent | a883a5a7ef1a09baa691c0a428d3dbb83eadd50c (diff) | |
download | Exchange-4f0b3ce2f4a913bc24870e7c331b0fdff5c6f1ca.tar.gz |
am a883a5a7: am 7f0b7b0d: Handle provisioning errors for all sync operations.
* commit 'a883a5a7ef1a09baa691c0a428d3dbb83eadd50c':
Handle provisioning errors for all sync operations.
-rw-r--r-- | src/com/android/exchange/eas/EasFolderSync.java | 19 | ||||
-rw-r--r-- | src/com/android/exchange/eas/EasOperation.java | 33 | ||||
-rw-r--r-- | src/com/android/exchange/eas/EasSync.java | 5 | ||||
-rw-r--r-- | src/com/android/exchange/service/EasSyncHandler.java | 59 |
4 files changed, 70 insertions, 46 deletions
diff --git a/src/com/android/exchange/eas/EasFolderSync.java b/src/com/android/exchange/eas/EasFolderSync.java index 696a4e72..1be9fe74 100644 --- a/src/com/android/exchange/eas/EasFolderSync.java +++ b/src/com/android/exchange/eas/EasFolderSync.java @@ -155,24 +155,11 @@ public class EasFolderSync extends EasOperation { @Override protected int handleResponse(final EasResponse response, final SyncResult syncResult) - throws IOException { + throws IOException, CommandStatusException { if (!response.isEmpty()) { - try { - new FolderSyncParser(mContext, mContext.getContentResolver(), - response.getInputStream(), mAccount, mStatusOnly).parse(); - } catch (final CommandStatusException e) { - final int status = e.mStatus; - LogUtils.e(LOG_TAG, "EasFolderSync.handleResponse status %d", status); - if (CommandStatusException.CommandStatus.isNeedsProvisioning(status)) { - return RESULT_PROVISIONING_ERROR; - } - if (CommandStatusException.CommandStatus.isDeniedAccess(status)) { - return RESULT_FORBIDDEN; - } - return RESULT_OTHER_FAILURE; - } + new FolderSyncParser(mContext, mContext.getContentResolver(), + response.getInputStream(), mAccount, mStatusOnly).parse(); } - return RESULT_OK; } diff --git a/src/com/android/exchange/eas/EasOperation.java b/src/com/android/exchange/eas/EasOperation.java index 37b7ead8..bf7b0134 100644 --- a/src/com/android/exchange/eas/EasOperation.java +++ b/src/com/android/exchange/eas/EasOperation.java @@ -33,6 +33,7 @@ import com.android.emailcommon.provider.EmailContent; import com.android.emailcommon.provider.HostAuth; import com.android.emailcommon.provider.Mailbox; import com.android.emailcommon.utility.Utility; +import com.android.exchange.CommandStatusException; import com.android.exchange.Eas; import com.android.exchange.EasResponse; import com.android.exchange.adapter.Serializer; @@ -220,22 +221,42 @@ public abstract class EasOperation { final int result; // First off, the success case. if (response.isSuccess()) { + int responseResult; try { - result = handleResponse(response, syncResult); - if (result >= 0) { - return result; - } + responseResult = handleResponse(response, syncResult); } catch (final IOException e) { LogUtils.e(LOG_TAG, e, "Exception while handling response"); if (syncResult != null) { ++syncResult.stats.numIoExceptions; } return RESULT_REQUEST_FAILURE; + } catch (final CommandStatusException e) { + // For some operations (notably Sync & FolderSync), errors are signaled in + // the payload of the response. These will have a HTTP 200 response, and the + // error condition is only detected during response parsing. + // The various parsers handle this by throwing a CommandStatusException. + // TODO: Consider having the parsers return the errors instead of throwing. + final int status = e.mStatus; + LogUtils.e(LOG_TAG, "CommandStatusException: %s, %d", getCommand(), status); + if (CommandStatusException.CommandStatus.isNeedsProvisioning(status)) { + responseResult = RESULT_PROVISIONING_ERROR; + } else if (CommandStatusException.CommandStatus.isDeniedAccess(status)) { + responseResult = RESULT_FORBIDDEN; + } else { + responseResult = RESULT_OTHER_FAILURE; + } } + result = responseResult; } else { result = RESULT_OTHER_FAILURE; } + // Non-negative results indicate success. Return immediately and bypass the error + // handling. + if (result >= 0) { + return result; + } + // If this operation has distinct handling for 403 errors, do that. if (result == RESULT_FORBIDDEN || (response.isForbidden() && handleForbidden())) { LogUtils.e(LOG_TAG, "Forbidden response"); @@ -251,6 +272,8 @@ public abstract class EasOperation { if (handleProvisionError(syncResult, mAccountId)) { // The provisioning error has been taken care of, so we should re-do this // request. + LogUtils.d(LOG_TAG, "Provisioning error handled during %s, retrying", + getCommand()); continue; } if (syncResult != null) { @@ -376,7 +399,7 @@ public abstract class EasOperation { * @throws IOException */ protected abstract int handleResponse(final EasResponse response, final SyncResult syncResult) - throws IOException; + throws IOException, CommandStatusException; /** * The following functions may be overriden by a subclass, but most operations will not need diff --git a/src/com/android/exchange/eas/EasSync.java b/src/com/android/exchange/eas/EasSync.java index 710f692f..63950923 100644 --- a/src/com/android/exchange/eas/EasSync.java +++ b/src/com/android/exchange/eas/EasSync.java @@ -183,7 +183,7 @@ public class EasSync extends EasOperation { @Override protected int handleResponse(final EasResponse response, final SyncResult syncResult) - throws IOException { + throws IOException, CommandStatusException { final Account account = Account.restoreAccountWithId(mContext, mAccountId); if (account == null) { // TODO: Make this some other error type, since the account is just gone now. @@ -200,9 +200,6 @@ public class EasSync extends EasOperation { mMessageUpdateStatus = parser.getMessageStatuses(); } catch (final Parser.EmptyStreamException e) { // This indicates a compressed response which was empty, which is OK. - } catch (final CommandStatusException e) { - // TODO: This is the wrong error type. - return RESULT_OTHER_FAILURE; } return 0; } diff --git a/src/com/android/exchange/service/EasSyncHandler.java b/src/com/android/exchange/service/EasSyncHandler.java index 0aefdb96..3f763a3d 100644 --- a/src/com/android/exchange/service/EasSyncHandler.java +++ b/src/com/android/exchange/service/EasSyncHandler.java @@ -84,13 +84,12 @@ public abstract class EasSyncHandler extends EasServerConnection { public static final int PIM_WINDOW_SIZE_CALENDAR = 10; // TODO: For each type of failure, provide info about why. + protected static final int SYNC_RESULT_DENIED = -3; + protected static final int SYNC_RESULT_PROVISIONING_ERROR = -2; protected static final int SYNC_RESULT_FAILED = -1; protected static final int SYNC_RESULT_DONE = 0; protected static final int SYNC_RESULT_MORE_AVAILABLE = 1; - /** Maximum number of Sync requests we'll send to the Exchange server in one sync attempt. */ - private static final int MAX_LOOPING_COUNT = 100; - protected final ContentResolver mContentResolver; protected final Mailbox mMailbox; protected final Bundle mSyncExtras; @@ -308,6 +307,15 @@ public abstract class EasSyncHandler extends EasServerConnection { } catch (final IOException e) { return SYNC_RESULT_FAILED; } catch (final CommandStatusException e) { + // TODO: This is basically copied from EasOperation, will go away when this merges. + final int status = e.mStatus; + LogUtils.e(TAG, "CommandStatusException: %d", status); + if (CommandStatusException.CommandStatus.isNeedsProvisioning(status)) { + return SYNC_RESULT_PROVISIONING_ERROR; + } + if (CommandStatusException.CommandStatus.isDeniedAccess(status)) { + return SYNC_RESULT_DENIED; + } return SYNC_RESULT_FAILED; } return SYNC_RESULT_DONE; @@ -340,35 +348,44 @@ public abstract class EasSyncHandler extends EasServerConnection { final int result; try { + final int responseResult; final int code = resp.getStatus(); if (code == HttpStatus.SC_OK) { // A successful sync can have an empty response -- this indicates no change. // In the case of a compressed stream, resp will be non-empty, but parse() handles // that case. if (!resp.isEmpty()) { - result = parse(resp); + responseResult = parse(resp); } else { - result = SYNC_RESULT_DONE; + responseResult = SYNC_RESULT_DONE; } } else { LogUtils.e(TAG, "Sync failed with Status: " + code); - if (resp.isProvisionError()) { - final EasProvision provision = new EasProvision(mContext, mAccount.mId, this); - if (provision.provision(syncResult, mAccount.mId)) { - // We handled the provisioning error, so loop. - result = SYNC_RESULT_MORE_AVAILABLE; - } else { - syncResult.stats.numAuthExceptions++; - return SYNC_RESULT_FAILED; // TODO: Handle SyncStatus.FAILURE_SECURITY; - } - } else if (resp.isAuthError()) { - syncResult.stats.numAuthExceptions++; - return SYNC_RESULT_FAILED; // TODO: Handle SyncStatus.FAILURE_LOGIN; + responseResult = SYNC_RESULT_FAILED; + } + + if (responseResult == SYNC_RESULT_DONE + || responseResult == SYNC_RESULT_MORE_AVAILABLE) { + result = responseResult; + } else if (resp.isProvisionError() + || responseResult == SYNC_RESULT_PROVISIONING_ERROR) { + final EasProvision provision = new EasProvision(mContext, mAccount.mId, this); + if (provision.provision(syncResult, mAccount.mId)) { + // We handled the provisioning error, so loop. + LogUtils.d(TAG, "Provisioning error handled during sync, retrying"); + result = SYNC_RESULT_MORE_AVAILABLE; } else { - syncResult.stats.numParseExceptions++; - return SYNC_RESULT_FAILED; // TODO: Handle SyncStatus.FAILURE_OTHER; + syncResult.stats.numAuthExceptions++; + result = SYNC_RESULT_FAILED; } + } else if (resp.isAuthError() || responseResult == SYNC_RESULT_DENIED) { + syncResult.stats.numAuthExceptions++; + result = SYNC_RESULT_FAILED; + } else { + syncResult.stats.numParseExceptions++; + result = SYNC_RESULT_FAILED; } + } finally { resp.close(); } @@ -385,8 +402,8 @@ public abstract class EasSyncHandler extends EasServerConnection { /** * Perform the sync, updating {@link #mSyncResult} as appropriate (which was passed in from * the system SyncManager and will be read by it on the way out). - * This function can send multiple Sync messages to the Exchange server, up to - * {@link #MAX_LOOPING_COUNT}, due to the server replying to a Sync request with MoreAvailable. + * This function can send multiple Sync messages to the Exchange server, due to the server + * replying to a Sync request with MoreAvailable. * In the case of errors, this function should not attempt any retries, but rather should * set {@link #mSyncResult} to reflect the problem and let the system SyncManager handle * any it. |