This commit is contained in:
commit
3c39402e4a
@ -82,11 +82,14 @@ public abstract class AbstractSyncService implements Runnable {
|
|||||||
public abstract void stop();
|
public abstract void stop();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sent by SyncManager to indicate that an alarm has fired for this service. Typically, this
|
* Sent by SyncManager to indicate that an alarm has fired for this service, and that its
|
||||||
* means that a network operation has timed out. The service is NOT stopped, but service
|
* pending (network) operation has timed out. The service is NOT automatically stopped,
|
||||||
* behavior is not otherwise defined (i.e. it's service dependent)
|
* although the behavior is service dependent.
|
||||||
|
*
|
||||||
|
* @return true if the operation was stopped normally; false if the thread needed to be
|
||||||
|
* interrupted.
|
||||||
*/
|
*/
|
||||||
public abstract void alarm();
|
public abstract boolean alarm();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sent by SyncManager to request that the service reset itself cleanly; the meaning of this
|
* Sent by SyncManager to request that the service reset itself cleanly; the meaning of this
|
||||||
|
@ -93,6 +93,7 @@ import java.io.File;
|
|||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.lang.Thread.State;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
import java.security.cert.CertificateException;
|
import java.security.cert.CertificateException;
|
||||||
@ -159,6 +160,9 @@ public class EasSyncService extends AbstractSyncService {
|
|||||||
|
|
||||||
static private final int PROTOCOL_PING_STATUS_COMPLETED = 1;
|
static private final int PROTOCOL_PING_STATUS_COMPLETED = 1;
|
||||||
|
|
||||||
|
// The amount of time we allow for a thread to release its post lock after receiving an alert
|
||||||
|
static private final int POST_LOCK_TIMEOUT = 10*SECONDS;
|
||||||
|
|
||||||
// Fallbacks (in minutes) for ping loop failures
|
// Fallbacks (in minutes) for ping loop failures
|
||||||
static private final int MAX_PING_FAILURES = 1;
|
static private final int MAX_PING_FAILURES = 1;
|
||||||
static private final int PING_FALLBACK_INBOX = 5;
|
static private final int PING_FALLBACK_INBOX = 5;
|
||||||
@ -182,7 +186,8 @@ public class EasSyncService extends AbstractSyncService {
|
|||||||
public ContentResolver mContentResolver;
|
public ContentResolver mContentResolver;
|
||||||
private String[] mBindArguments = new String[2];
|
private String[] mBindArguments = new String[2];
|
||||||
private ArrayList<String> mPingChangeList;
|
private ArrayList<String> mPingChangeList;
|
||||||
private HttpPost mPendingPost = null;
|
// The HttpPost in progress
|
||||||
|
private volatile HttpPost mPendingPost = null;
|
||||||
// The ping time (in seconds)
|
// The ping time (in seconds)
|
||||||
private int mPingHeartbeat = PING_STARTING_HEARTBEAT;
|
private int mPingHeartbeat = PING_STARTING_HEARTBEAT;
|
||||||
// The longest successful ping heartbeat
|
// The longest successful ping heartbeat
|
||||||
@ -221,25 +226,69 @@ public class EasSyncService extends AbstractSyncService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void alarm() {
|
/**
|
||||||
|
* Try to wake up a sync thread that is waiting on an HttpClient POST and has waited past its
|
||||||
|
* socket timeout without having thrown an Exception
|
||||||
|
*
|
||||||
|
* @return true if the POST was successfully stopped; false if we've failed and interrupted
|
||||||
|
* the thread
|
||||||
|
*/
|
||||||
|
public boolean alarm() {
|
||||||
|
HttpPost post;
|
||||||
|
String threadName = mThread.getName();
|
||||||
|
|
||||||
|
// Synchronize here so that we are guaranteed to have valid mPendingPost and mPostLock
|
||||||
|
// executePostWithTimeout (which executes the HttpPost) also uses this lock
|
||||||
synchronized(getSynchronizer()) {
|
synchronized(getSynchronizer()) {
|
||||||
if (mPendingPost != null) {
|
// Get a reference to the current post lock
|
||||||
URI uri = mPendingPost.getURI();
|
post = mPendingPost;
|
||||||
|
if (post != null) {
|
||||||
|
if (Eas.USER_LOG) {
|
||||||
|
URI uri = post.getURI();
|
||||||
if (uri != null) {
|
if (uri != null) {
|
||||||
String query = uri.getQuery();
|
String query = uri.getQuery();
|
||||||
if (query == null) {
|
if (query == null) {
|
||||||
query = "POST";
|
query = "POST";
|
||||||
}
|
}
|
||||||
userLog("Alert, aborting " + query);
|
userLog(threadName, ": Alert, aborting ", query);
|
||||||
} else {
|
} else {
|
||||||
userLog("Alert, no URI?");
|
userLog(threadName, ": Alert, no URI?");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
// Abort the POST
|
||||||
mPostAborted = true;
|
mPostAborted = true;
|
||||||
mPendingPost.abort();
|
post.abort();
|
||||||
} else {
|
} else {
|
||||||
|
// If there's no POST, we're done
|
||||||
userLog("Alert, no pending POST");
|
userLog("Alert, no pending POST");
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Wait for the POST to finish
|
||||||
|
try {
|
||||||
|
Thread.sleep(POST_LOCK_TIMEOUT);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
}
|
||||||
|
|
||||||
|
State s = mThread.getState();
|
||||||
|
if (Eas.USER_LOG) {
|
||||||
|
userLog(threadName + ": State = " + s.name());
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized (getSynchronizer()) {
|
||||||
|
// If the thread is still hanging around and the same post is pending, let's try to
|
||||||
|
// stop the thread with an interrupt.
|
||||||
|
if ((s != State.TERMINATED) && (mPendingPost != null) && (mPendingPost == post)) {
|
||||||
|
mStop = true;
|
||||||
|
mThread.interrupt();
|
||||||
|
userLog("Interrupting...");
|
||||||
|
// Let the caller know we had to interrupt the thread
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Let the caller know that the alarm was handled normally
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1431,7 +1431,14 @@ public class SyncManager extends Service implements Runnable {
|
|||||||
}
|
}
|
||||||
service.mAccount = Account.restoreAccountWithId(INSTANCE, m.mAccountKey);
|
service.mAccount = Account.restoreAccountWithId(INSTANCE, m.mAccountKey);
|
||||||
service.mMailbox = m;
|
service.mMailbox = m;
|
||||||
service.alarm();
|
// Send the alarm to the sync service
|
||||||
|
if (!service.alarm()) {
|
||||||
|
// A false return means that we were forced to interrupt the thread
|
||||||
|
// In this case, we release the mailbox so that we can start another
|
||||||
|
// thread to do the work
|
||||||
|
log("Alarm failed; releasing mailbox");
|
||||||
|
syncManager.releaseMailbox(id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}}).start();
|
}}).start();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user