Bug 825598 - Add a watchdog timer on downloads and automatically restart if timer expires. r=marshall_law, a=bb+
authorDave Hylands <dhylands@gmail.com>
Tue, 15 Jan 2013 00:10:19 +0100
changeset 118175 f2460bf17811
parent 118174 4c66309f7ba1
child 118176 f630a969cef9
push id259
push userjst@mozilla.com
push date2013-01-15 05:59 +0000
reviewersmarshall_law, bb
bugs825598
milestone18.0
Bug 825598 - Add a watchdog timer on downloads and automatically restart if timer expires. r=marshall_law, a=bb+
b2g/app/b2g.js
b2g/components/UpdatePrompt.js
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -458,16 +458,19 @@ pref("marionette.defaultPrefs.port", 282
 #ifdef MOZ_UPDATER
 // When we're applying updates, we can't let anything hang us on
 // quit+restart.  The user has no recourse.
 pref("shutdown.watchdog.timeoutSecs", 5);
 // Timeout before the update prompt automatically installs the update
 pref("b2g.update.apply-prompt-timeout", 60000); // milliseconds
 // Amount of time to wait after the user is idle before prompting to apply an update
 pref("b2g.update.apply-idle-timeout", 600000); // milliseconds
+// Amount of time after which connection will be restarted if no progress
+pref("b2g.update.download-watchdog-timeout", 120000); // milliseconds
+pref("b2g.update.download-watchdog-max-retries", 5);
 
 pref("app.update.enabled", true);
 pref("app.update.auto", false);
 pref("app.update.silent", false);
 pref("app.update.mode", 0);
 pref("app.update.incompatible.mode", 0);
 pref("app.update.staging.enabled", true);
 pref("app.update.service.enabled", true);
--- a/b2g/components/UpdatePrompt.js
+++ b/b2g/components/UpdatePrompt.js
@@ -13,18 +13,20 @@ Cu.import("resource://gre/modules/XPCOMU
 Cu.import("resource://gre/modules/Services.jsm");
 
 const VERBOSE = 1;
 let log =
   VERBOSE ?
   function log_dump(msg) { dump("UpdatePrompt: "+ msg +"\n"); } :
   function log_noop(msg) { };
 
-const PREF_APPLY_PROMPT_TIMEOUT = "b2g.update.apply-prompt-timeout";
-const PREF_APPLY_IDLE_TIMEOUT   = "b2g.update.apply-idle-timeout";
+const PREF_APPLY_PROMPT_TIMEOUT          = "b2g.update.apply-prompt-timeout";
+const PREF_APPLY_IDLE_TIMEOUT            = "b2g.update.apply-idle-timeout";
+const PREF_DOWNLOAD_WATCHDOG_TIMEOUT     = "b2g.update.download-watchdog-timeout";
+const PREF_DOWNLOAD_WATCHDOG_MAX_RETRIES = "b2g.update.download-watchdog-max-retries";
 
 const NETWORK_ERROR_OFFLINE = 111;
 const FILE_ERROR_TOO_BIG    = 112;
 const HTTP_ERROR_OFFSET     = 1000;
 
 const STATE_DOWNLOADING = 'downloading';
 
 XPCOMUtils.defineLazyServiceGetter(Services, "aus",
@@ -484,35 +486,102 @@ UpdatePrompt.prototype = {
     timer.initWithCallback(this, aTimeoutMs, timer.TYPE_ONE_SHOT);
     return timer;
   },
 
   // nsIRequestObserver
 
   _startedSent: false,
 
+  _watchdogTimer: null,
+  _watchdogTimeout: 0,
+
+  _autoRestartDownload: false,
+  _autoRestartCount: 0,
+
+  watchdogTimerFired: function UP_watchdogTimerFired() {
+    log("Download watchdog fired");
+    this._autoRestartDownload = true;
+    Services.aus.pauseDownload();
+  },
+
+  startWatchdogTimer: function UP_startWatchdogTimer() {
+    if (this._watchdogTimer) {
+      this._watchdogTimer.cancel();
+    } else {
+      this._watchdogTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
+      this._watchdogTimeout = Services.prefs.getIntPref(PREF_DOWNLOAD_WATCHDOG_TIMEOUT);
+    }
+    this._watchdogTimer.initWithCallback(this.watchdogTimerFired.bind(this),
+                                         this._watchdogTimeout,
+                                         Ci.nsITimer.TYPE_ONE_SHOT);
+  },
+
+  stopWatchdogTimer: function UP_stopWatchdogTimer() {
+    if (this._watchdogTimer) {
+      this._watchdogTimer.cancel();
+      this._watchdogTimer = null;
+    }
+  },
+
+  touchWatchdogTimer: function UP_touchWatchdogTimer() {
+    this.startWatchdogTimer();
+  },
+
   onStartRequest: function UP_onStartRequest(aRequest, aContext) {
     // Wait until onProgress to send the update-download-started event, in case
     // this request turns out to fail for some reason
     this._startedSent = false;
+    this.startWatchdogTimer();
   },
 
   onStopRequest: function UP_onStopRequest(aRequest, aContext, aStatusCode) {
+    this.stopWatchdogTimer();
+    Services.aus.removeDownloadListener(this);
     let paused = !Components.isSuccessCode(aStatusCode);
+    if (!paused) {
+      // The download was successful, no need to restart
+      this._autoRestartDownload = false;
+    }
+    if (this._autoRestartDownload) {
+      this._autoRestartDownload = false;
+      let watchdogMaxRetries = Services.prefs.getIntPref(PREF_DOWNLOAD_WATCHDOG_MAX_RETRIES);
+      this._autoRestartCount++;
+      if (this._autoRestartCount > watchdogMaxRetries) {
+        log("Download - retry count exceeded - error");
+        // We exceeded the max retries. Treat the download like an error,
+        // which will give the user a chance to restart manually later.
+        this._autoRestartCount = 0;
+        if (Services.um.activeUpdate) {
+          this.showUpdateError(Services.um.activeUpdate);
+        }
+        return;
+      }
+      log("Download - restarting download - attempt " + this._autoRestartCount);
+      this.downloadUpdate(null);
+      return;
+    }
+    this._autoRestartCount = 0;
     this.sendChromeEvent("update-download-stopped", {
-        paused: paused
+      paused: paused
     });
-
-    Services.aus.removeDownloadListener(this);
   },
 
   // nsIProgressEventSink
 
   onProgress: function UP_onProgress(aRequest, aContext, aProgress,
                                      aProgressMax) {
+    if (aProgress == aProgressMax) {
+      // The update.mar validation done by onStopRequest may take
+      // a while before the onStopRequest callback is made, so stop
+      // the timer now.
+      this.stopWatchdogTimer();
+    } else {
+      this.touchWatchdogTimer();
+    }
     if (!this._startedSent) {
       this.sendChromeEvent("update-download-started", {
         total: aProgressMax
       });
       this._startedSent = true;
     }
 
     this.sendChromeEvent("update-download-progress", {