am 7a1a2037: am e43b11ba: Handle correction of rejected Ping heartbeat

Merge commit '7a1a203786f10b60393efdec606cea416aa99e16' into gingerbread-plus-aosp

* commit '7a1a203786f10b60393efdec606cea416aa99e16':
  Handle correction of rejected Ping heartbeat
This commit is contained in:
Marc Blank 2010-07-14 22:39:06 -07:00 committed by Android Git Automerger
commit 84f7d07d4f
4 changed files with 142 additions and 16 deletions

View File

@ -153,10 +153,7 @@ public class EasSyncService extends AbstractSyncService {
static private final int PING_MINUTES = 60; // in seconds
static private final int PING_FUDGE_LOW = 10;
static private final int PING_STARTING_HEARTBEAT = (8*PING_MINUTES)-PING_FUDGE_LOW;
static private final int PING_MIN_HEARTBEAT = (5*PING_MINUTES)-PING_FUDGE_LOW;
static private final int PING_MAX_HEARTBEAT = (17*PING_MINUTES)-PING_FUDGE_LOW;
static private final int PING_HEARTBEAT_INCREMENT = 3*PING_MINUTES;
static private final int PING_FORCE_HEARTBEAT = 2*PING_MINUTES;
// Maximum number of times we'll allow a sync to "loop" with MoreAvailable true before
// forcing it to stop. This number has been determined empirically.
@ -192,12 +189,18 @@ public class EasSyncService extends AbstractSyncService {
private ArrayList<String> mPingChangeList;
// The HttpPost in progress
private volatile HttpPost mPendingPost = null;
// Our heartbeat when we are waiting for ping boxes to be ready
/*package*/ int mPingForceHeartbeat = 2*PING_MINUTES;
// The minimum heartbeat we will send
/*package*/ int mPingMinHeartbeat = (5*PING_MINUTES)-PING_FUDGE_LOW;
// The maximum heartbeat we will send
/*package*/ int mPingMaxHeartbeat = (17*PING_MINUTES)-PING_FUDGE_LOW;
// The ping time (in seconds)
private int mPingHeartbeat = PING_STARTING_HEARTBEAT;
/*package*/ int mPingHeartbeat = PING_STARTING_HEARTBEAT;
// The longest successful ping heartbeat
private int mPingHighWaterMark = 0;
// Whether we've ever lowered the heartbeat
private boolean mPingHeartbeatDropped = false;
/*package*/ boolean mPingHeartbeatDropped = false;
// Whether a POST was aborted due to alarm (watchdog alarm)
private boolean mPostAborted = false;
// Whether a POST was aborted due to reset
@ -1541,6 +1544,10 @@ public class EasSyncService extends AbstractSyncService {
} catch (StaleFolderListException e) {
// We break out if we get told about a stale folder list
userLog("Ping interrupted; folder list requires sync...");
} catch (IllegalHeartbeatException e) {
// If we're sending an illegal heartbeat, reset either the min or the max to
// that heartbeat
resetHeartbeats(e.mLegalHeartbeat);
} finally {
Thread.currentThread().setName(threadName);
}
@ -1561,6 +1568,44 @@ public class EasSyncService extends AbstractSyncService {
}
}
/**
* Reset either our minimum or maximum ping heartbeat to a heartbeat known to be legal
* @param legalHeartbeat a known legal heartbeat (from the EAS server)
*/
/*package*/ void resetHeartbeats(int legalHeartbeat) {
userLog("Resetting min/max heartbeat, legal = " + legalHeartbeat);
// We are here because the current heartbeat (mPingHeartbeat) is invalid. Depending on
// whether the argument is above or below the current heartbeat, we can infer the need to
// change either the minimum or maximum heartbeat
if (legalHeartbeat > mPingHeartbeat) {
// The legal heartbeat is higher than the ping heartbeat; therefore, our minimum was
// too low. We respond by raising either or both of the minimum heartbeat or the
// force heartbeat to the argument value
if (mPingMinHeartbeat < legalHeartbeat) {
mPingMinHeartbeat = legalHeartbeat;
}
if (mPingForceHeartbeat < legalHeartbeat) {
mPingForceHeartbeat = legalHeartbeat;
}
// If our minimum is now greater than the max, bring them together
if (mPingMinHeartbeat > mPingMaxHeartbeat) {
mPingMaxHeartbeat = legalHeartbeat;
}
} else if (legalHeartbeat < mPingHeartbeat) {
// The legal heartbeat is lower than the ping heartbeat; therefore, our maximum was
// too high. We respond by lowering the maximum to the argument value
mPingMaxHeartbeat = legalHeartbeat;
// If our maximum is now less than the minimum, bring them together
if (mPingMaxHeartbeat < mPingMinHeartbeat) {
mPingMinHeartbeat = legalHeartbeat;
}
}
// Set current heartbeat to the legal heartbeat
mPingHeartbeat = legalHeartbeat;
// Allow the heartbeat logic to run
mPingHeartbeatDropped = false;
}
private void pushFallback(long mailboxId) {
Mailbox mailbox = Mailbox.restoreMailboxWithId(mContext, mailboxId);
if (mailbox == null) {
@ -1593,7 +1638,8 @@ public class EasSyncService extends AbstractSyncService {
return false;
}
private void runPingLoop() throws IOException, StaleFolderListException {
private void runPingLoop() throws IOException, StaleFolderListException,
IllegalHeartbeatException {
int pingHeartbeat = mPingHeartbeat;
userLog("runPingLoop");
// Do push for all sync services here
@ -1693,7 +1739,7 @@ public class EasSyncService extends AbstractSyncService {
userLog("Forcing ping after waiting for all boxes to be ready");
}
HttpResponse res =
sendPing(s.toByteArray(), forcePing ? PING_FORCE_HEARTBEAT : pingHeartbeat);
sendPing(s.toByteArray(), forcePing ? mPingForceHeartbeat : pingHeartbeat);
int code = res.getStatusLine().getStatusCode();
userLog("Ping response: ", code);
@ -1719,11 +1765,11 @@ public class EasSyncService extends AbstractSyncService {
mPingHighWaterMark = pingHeartbeat;
userLog("Setting high water mark at: ", mPingHighWaterMark);
}
if ((pingHeartbeat < PING_MAX_HEARTBEAT) &&
if ((pingHeartbeat < mPingMaxHeartbeat) &&
!mPingHeartbeatDropped) {
pingHeartbeat += PING_HEARTBEAT_INCREMENT;
if (pingHeartbeat > PING_MAX_HEARTBEAT) {
pingHeartbeat = PING_MAX_HEARTBEAT;
if (pingHeartbeat > mPingMaxHeartbeat) {
pingHeartbeat = mPingMaxHeartbeat;
}
userLog("Increasing ping heartbeat to ", pingHeartbeat, "s");
}
@ -1748,12 +1794,12 @@ public class EasSyncService extends AbstractSyncService {
// ping.
} else if (mPostAborted || isLikelyNatFailure(message)) {
long pingLength = SystemClock.elapsedRealtime() - pingTime;
if ((pingHeartbeat > PING_MIN_HEARTBEAT) &&
if ((pingHeartbeat > mPingMinHeartbeat) &&
(pingHeartbeat > mPingHighWaterMark)) {
pingHeartbeat -= PING_HEARTBEAT_INCREMENT;
mPingHeartbeatDropped = true;
if (pingHeartbeat < PING_MIN_HEARTBEAT) {
pingHeartbeat = PING_MIN_HEARTBEAT;
if (pingHeartbeat < mPingMinHeartbeat) {
pingHeartbeat = mPingMinHeartbeat;
}
userLog("Decreased ping heartbeat to ", pingHeartbeat, "s");
} else if (mPostAborted) {
@ -1823,7 +1869,7 @@ public class EasSyncService extends AbstractSyncService {
private int parsePingResult(InputStream is, ContentResolver cr,
HashMap<String, Integer> errorMap)
throws IOException, StaleFolderListException {
throws IOException, StaleFolderListException, IllegalHeartbeatException {
PingParser pp = new PingParser(is, this);
if (pp.parse()) {
// True indicates some mailboxes need syncing...

View File

@ -0,0 +1,27 @@
/*
* Copyright (C) 2010 The Android Open Source Project
* Licensed to The Android Open Source Project.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.exchange;
public class IllegalHeartbeatException extends EasException {
private static final long serialVersionUID = 1L;
public final int mLegalHeartbeat;
public IllegalHeartbeatException(int legalHeartbeat) {
mLegalHeartbeat = legalHeartbeat;
}
}

View File

@ -17,6 +17,7 @@
package com.android.exchange.adapter;
import com.android.exchange.EasSyncService;
import com.android.exchange.IllegalHeartbeatException;
import com.android.exchange.StaleFolderListException;
import java.io.IOException;
@ -62,7 +63,7 @@ public class PingParser extends Parser {
}
@Override
public boolean parse() throws IOException, StaleFolderListException {
public boolean parse() throws IOException, StaleFolderListException, IllegalHeartbeatException {
boolean res = false;
if (nextTag(START_DOCUMENT) != Tags.PING_PING) {
throw new IOException();
@ -77,9 +78,15 @@ public class PingParser extends Parser {
} else if (status == 7 || status == 4) {
// Status of 7 or 4 indicate a stale folder list
throw new StaleFolderListException();
} else if (status == 5) {
// Status 5 means our heartbeat is beyond allowable limits
// In this case, there will be a heartbeat interval set
}
} else if (tag == Tags.PING_FOLDERS) {
parsePingFolders(syncList);
} else if (tag == Tags.PING_HEARTBEAT_INTERVAL) {
// Throw an exception, saving away the legal heartbeat interval specified
throw new IllegalHeartbeatException(getValueInt());
} else {
skipTag();
}

View File

@ -23,7 +23,11 @@ import android.test.AndroidTestCase;
import java.io.File;
import java.io.IOException;
public class EasSyncServiceTests extends AndroidTestCase {
/**
* You can run this entire test case with:
* runtest -c com.android.exchange.EasSyncServiceTests email
*/
public class EasSyncServiceTests extends AndroidTestCase {
Context mMockContext;
@Override
@ -73,4 +77,46 @@ public class EasSyncServiceTests extends AndroidTestCase {
}
}
}
public void testResetHeartbeats() {
EasSyncService svc = new EasSyncService();
// Test case in which the minimum and force heartbeats need to come up
svc.mPingMaxHeartbeat = 1000;
svc.mPingMinHeartbeat = 200;
svc.mPingHeartbeat = 300;
svc.mPingForceHeartbeat = 100;
svc.mPingHeartbeatDropped = true;
svc.resetHeartbeats(400);
assertEquals(400, svc.mPingMinHeartbeat);
assertEquals(1000, svc.mPingMaxHeartbeat);
assertEquals(400, svc.mPingHeartbeat);
assertEquals(400, svc.mPingForceHeartbeat);
assertFalse(svc.mPingHeartbeatDropped);
// Test case in which the force heartbeat needs to come up
svc.mPingMaxHeartbeat = 1000;
svc.mPingMinHeartbeat = 200;
svc.mPingHeartbeat = 100;
svc.mPingForceHeartbeat = 100;
svc.mPingHeartbeatDropped = true;
svc.resetHeartbeats(150);
assertEquals(200, svc.mPingMinHeartbeat);
assertEquals(1000, svc.mPingMaxHeartbeat);
assertEquals(150, svc.mPingHeartbeat);
assertEquals(150, svc.mPingForceHeartbeat);
assertFalse(svc.mPingHeartbeatDropped);
// Test case in which the maximum needs to come down
svc.mPingMaxHeartbeat = 1000;
svc.mPingMinHeartbeat = 200;
svc.mPingHeartbeat = 800;
svc.mPingForceHeartbeat = 100;
svc.mPingHeartbeatDropped = true;
svc.resetHeartbeats(600);
assertEquals(200, svc.mPingMinHeartbeat);
assertEquals(600, svc.mPingMaxHeartbeat);
assertEquals(600, svc.mPingHeartbeat);
assertEquals(100, svc.mPingForceHeartbeat);
assertFalse(svc.mPingHeartbeatDropped);
}
}