summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYu Ping Hu <yph@google.com>2013-11-15 13:43:03 -0800
committerAndroid Git Automerger <android-git-automerger@android.com>2013-11-15 13:43:03 -0800
commit4f0b3ce2f4a913bc24870e7c331b0fdff5c6f1ca (patch)
tree4fd2b241bb3987cfc002843e7dc264b8a0640723
parent27e2eac60a113ef89f0603d6a2da9884385810b7 (diff)
parenta883a5a7ef1a09baa691c0a428d3dbb83eadd50c (diff)
downloadExchange-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.java19
-rw-r--r--src/com/android/exchange/eas/EasOperation.java33
-rw-r--r--src/com/android/exchange/eas/EasSync.java5
-rw-r--r--src/com/android/exchange/service/EasSyncHandler.java59
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.