Fix connection failure retry behavior; don't try syncing w/o connectivity

* Also remove some logging and correct some erroneous logging
* Fix the backoff behavior on IOException

Change-Id: I5fb5a0bf73eaa681eb7b9c305c838e78e7ba88ab
diff --git a/src/com/android/exchange/EasSyncService.java b/src/com/android/exchange/EasSyncService.java
index be250b6..9bad287 100644
--- a/src/com/android/exchange/EasSyncService.java
+++ b/src/com/android/exchange/EasSyncService.java
@@ -551,7 +551,6 @@
                      if (len > 0) {
                          InputStream is = entity.getContent();
                          // Returns true if we need to sync again
-                         userLog("FolderSync, deviceId = ", mDeviceId);
                          if (new FolderSyncParser(is, new AccountSyncAdapter(mMailbox, this))
                                  .parse()) {
                              continue;
@@ -764,8 +763,8 @@
                             // try increasing timeout by two minutes
                             if ((status == PROTOCOL_PING_STATUS_COMPLETED) &&
                                     (pingHeartbeat > mPingHighWaterMark)) {
-                                userLog("Setting ping high water mark at: ", mPingHighWaterMark);
                                 mPingHighWaterMark = pingHeartbeat;
+                                userLog("Setting ping high water mark at: ", mPingHighWaterMark);
                             }
                             if ((status == PROTOCOL_PING_STATUS_COMPLETED) &&
                                     (pingHeartbeat < PING_MAX_HEARTBEAT) &&
@@ -962,7 +961,6 @@
             target.sendLocalChanges(s);
 
             s.end().end().end().done();
-            userLog("Sync, deviceId = ", mDeviceId);
             HttpResponse resp = sendHttpClientPost("Sync", s.toByteArray());
             int code = resp.getStatusLine().getStatusCode();
             if (code == HttpStatus.SC_OK) {
diff --git a/src/com/android/exchange/SyncManager.java b/src/com/android/exchange/SyncManager.java
index 3c4cb13..c5e0513 100644
--- a/src/com/android/exchange/SyncManager.java
+++ b/src/com/android/exchange/SyncManager.java
@@ -117,8 +117,7 @@
     private static final int CONNECTIVITY_WAIT_TIME = 10*MINUTES;
 
     // Sync hold constants for services with transient errors
-    private static final int HOLD_DELAY_ESCALATION = 30*SECONDS;
-    private static final int HOLD_DELAY_MAXIMUM = 3*MINUTES;
+    private static final int HOLD_DELAY_MAXIMUM = 4*MINUTES;
 
     // Reason codes when SyncManager.kick is called (mainly for debugging)
     // UI has changed data, requiring an upsync of changes
@@ -166,6 +165,7 @@
     private static Object sSyncToken = new Object();
     // All threads can use this lock to wait for connectivity
     public static Object sConnectivityLock = new Object();
+    public static boolean sConnectivityHold = false;
 
     // Keeps track of running services (by mailbox id)
     private HashMap<Long, AbstractSyncService> mServiceMap =
@@ -203,6 +203,8 @@
 
     // The reason for SyncManager's next wakeup call
     private String mNextWaitReason;
+    // Whether we have an unsatisfied "kick" pending
+    private boolean mKicked = false;
 
     // Receiver of connectivity broadcasts
     private ConnectivityReceiver mConnectivityReceiver = null;
@@ -572,21 +574,20 @@
     class SyncError {
         int reason;
         boolean fatal = false;
-        long holdEndTime;
-        long holdDelay = 0;
+        long holdDelay = 15*SECONDS;
+        long holdEndTime = System.currentTimeMillis() + holdDelay;
 
         SyncError(int _reason, boolean _fatal) {
             reason = _reason;
             fatal = _fatal;
-            escalate();
         }
 
         /**
-         * We increase the hold on I/O errors in 30 second increments to 5 minutes
+         * We double the holdDelay from 15 seconds through 4 mins
          */
         void escalate() {
             if (holdDelay < HOLD_DELAY_MAXIMUM) {
-                holdDelay += HOLD_DELAY_ESCALATION;
+                holdDelay *= 2;
             }
             holdEndTime = System.currentTimeMillis() + holdDelay;
         }
@@ -1081,6 +1082,8 @@
     }
 
     private void startService(Mailbox m, int reason, PartRequest req) {
+        // Don't sync if there's no connectivity
+        if (sConnectivityHold) return;
         synchronized (sSyncToken) {
             Account acct = Account.restoreAccountWithId(this, m.mAccountKey);
             if (acct != null) {
@@ -1126,7 +1129,7 @@
                 (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
             NetworkInfo info = cm.getActiveNetworkInfo();
             if (info != null) {
-                log("NetworkInfo: " + info.getTypeName() + ", " + info.getState().name());
+                //log("NetworkInfo: " + info.getTypeName() + ", " + info.getState().name());
                 return;
             } else {
 
@@ -1141,9 +1144,12 @@
                     runAsleep(SYNC_MANAGER_ID, CONNECTIVITY_WAIT_TIME+5*SECONDS);
                     try {
                         log("Connectivity lock...");
+                        sConnectivityHold = true;
                         sConnectivityLock.wait(CONNECTIVITY_WAIT_TIME);
                         log("Connectivity lock released...");
                     } catch (InterruptedException e) {
+                    } finally {
+                        sConnectivityHold = false;
                     }
                     runAwake(SYNC_MANAGER_ID);
                 }
@@ -1193,20 +1199,29 @@
                 long nextWait = checkMailboxes();
                 try {
                     synchronized (this) {
-                        if (nextWait < 0) {
-                            log("Negative wait? Setting to 1s");
-                            nextWait = 1*SECONDS;
+                        if (!mKicked) {
+                            if (nextWait < 0) {
+                                log("Negative wait? Setting to 1s");
+                                nextWait = 1*SECONDS;
+                            }
+                            if (nextWait > 30*SECONDS) {
+                                runAsleep(SYNC_MANAGER_ID, nextWait - 1000);
+                            }
+                            if (nextWait != SYNC_MANAGER_HEARTBEAT_TIME) {
+                                log("Next awake in " + nextWait / 1000 + "s: " + mNextWaitReason);
+                            }
+                            wait(nextWait);
                         }
-                        if (nextWait > 30*SECONDS) {
-                            runAsleep(SYNC_MANAGER_ID, nextWait - 1000);
-                        }
-                        if (nextWait != SYNC_MANAGER_HEARTBEAT_TIME) {
-                            log("Next awake in " + nextWait / 1000 + "s: " + mNextWaitReason);
-                        }
-                        wait(nextWait);
                     }
                 } catch (InterruptedException e) {
                     // Needs to be caught, but causes no problem
+                } finally {
+                    synchronized (this) {
+                        if (mKicked) {
+                            //log("Wait deferred due to kick");
+                            mKicked = false;
+                        }
+                    }
                 }
             }
             stopServices();
@@ -1314,8 +1329,8 @@
                             }
                             continue;
                         } else {
-                            // The hold has ended; remove from the error map
-                            mSyncErrorMap.remove(mid);
+                            // Keep the error around, but clear the end time
+                            syncError.holdEndTime = 0;
                         }
                     }
                     long freq = c.getInt(Mailbox.CONTENT_SYNC_INTERVAL_COLUMN);
@@ -1512,6 +1527,7 @@
     static public void kick(String reason) {
         if (INSTANCE != null) {
             synchronized (INSTANCE) {
+                INSTANCE.mKicked = true;
                 INSTANCE.notify();
             }
         }