Bug 701092 - Limit session restore attempts. r=mfinkle
authorBrian Nicholson <bnicholson@mozilla.com>
Fri, 27 Jan 2012 22:04:54 -0800
changeset 85603 ededf3963a98c8c33aff8378cfe864d858ad270d
parent 85602 c8ea6b7164bca65531664fa4de77d77b5303f757
child 85604 bcd556d831090f8bc73b5cc7b233d3d03667f64f
push id5420
push userbnicholson@mozilla.com
push dateSat, 28 Jan 2012 06:05:09 +0000
treeherdermozilla-inbound@ededf3963a98 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmfinkle
bugs701092
milestone12.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 701092 - Limit session restore attempts. r=mfinkle
mobile/android/app/mobile.js
mobile/android/chrome/content/browser.js
mobile/android/components/SessionStore.idl
mobile/android/components/SessionStore.js
widget/android/nsAppShell.cpp
--- a/mobile/android/app/mobile.js
+++ b/mobile/android/app/mobile.js
@@ -145,16 +145,18 @@ pref("browser.sessionhistory.max_total_v
 pref("browser.sessionhistory.max_entries", 50);
 
 /* session store */
 pref("browser.sessionstore.resume_session_once", false);
 pref("browser.sessionstore.resume_from_crash", true);
 pref("browser.sessionstore.resume_from_crash_timeout", 60); // minutes
 pref("browser.sessionstore.interval", 10000); // milliseconds
 pref("browser.sessionstore.max_tabs_undo", 1);
+pref("browser.sessionstore.max_resumed_crashes", 1);
+pref("browser.sessionstore.recent_crashes", 0);
 
 /* these should help performance */
 pref("mozilla.widget.force-24bpp", true);
 pref("mozilla.widget.use-buffer-pixmap", true);
 pref("mozilla.widget.disable-native-theme", true);
 pref("layout.reflow.synthMouseMove", false);
 
 /* download manager (don't show the window or alert) */
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -264,62 +264,64 @@ var BrowserApp = {
     CharacterEncoding.init();
 
     // Init LoginManager
     Cc["@mozilla.org/login-manager;1"].getService(Ci.nsILoginManager);
     // Init FormHistory
     Cc["@mozilla.org/satchel/form-history;1"].getService(Ci.nsIFormHistory2);
 
     let url = "about:home";
-    let restoreSession = false;
+    let forceRestore = false;
     if ("arguments" in window) {
       if (window.arguments[0])
         url = window.arguments[0];
       if (window.arguments[1])
-        restoreSession = window.arguments[1];
+        forceRestore = window.arguments[1];
       if (window.arguments[2])
         gScreenWidth = window.arguments[2];
       if (window.arguments[3])
         gScreenHeight = window.arguments[3];
     }
 
     // XXX maybe we don't do this if the launch was kicked off from external
     Services.io.offline = false;
 
     // Broadcast a UIReady message so add-ons know we are finished with startup
     let event = document.createEvent("Events");
     event.initEvent("UIReady", true, false);
     window.dispatchEvent(event);
 
     // restore the previous session
     let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
-    if (restoreSession || ss.shouldRestore()) {
+    if (forceRestore || ss.shouldRestore()) {
       // A restored tab should not be active if we are loading a URL
       let restoreToFront = false;
 
       // Open any commandline URLs, except the homepage
       if (url && url != "about:home") {
         this.addTab(url);
       } else {
         // Let the session make a restored tab active
         restoreToFront = true;
-
-        // Be ready to handle any restore failures by making sure we have a valid tab opened
-        let restoreCleanup = {
-          observe: function(aSubject, aTopic, aData) {
-            Services.obs.removeObserver(restoreCleanup, "sessionstore-windows-restored");
-            if (aData == "fail")
-              BrowserApp.addTab("about:home");
+      }
+
+      // Be ready to handle any restore failures by making sure we have a valid tab opened
+      let restoreCleanup = {
+        observe: function(aSubject, aTopic, aData) {
+          Services.obs.removeObserver(restoreCleanup, "sessionstore-windows-restored");
+          if (aData == "fail") {
+            let params = { selected: restoreToFront };
+            BrowserApp.addTab("about:home");
           }
-        };
-        Services.obs.addObserver(restoreCleanup, "sessionstore-windows-restored", false);
-      }
+        }
+      };
+      Services.obs.addObserver(restoreCleanup, "sessionstore-windows-restored", false);
 
       // Start the restore
-      ss.restoreLastSession(restoreToFront);
+      ss.restoreLastSession(restoreToFront, forceRestore);
     } else {
       this.addTab(url);
 
       // show telemetry door hanger if we aren't restoring a session
       this._showTelemetryPrompt();
     }
 
     // notify java that gecko has loaded
--- a/mobile/android/components/SessionStore.idl
+++ b/mobile/android/components/SessionStore.idl
@@ -106,11 +106,12 @@ interface nsISessionStore : nsISupports
   /**
    * @returns A boolean indicating we should restore previous browser session
    */
   boolean shouldRestore();
 
   /**
    * Restores the previous browser session using a fast, lightweight strategy
    * @param aBringToFront should a restored tab be brought to the foreground?
+   * @param aForceRestore  whether we need to force a restore, regardless of the recent crash situation
    */
-  void restoreLastSession(in boolean aBringToFront);
+  void restoreLastSession(in boolean aBringToFront, in boolean aForceRestore);
 };
--- a/mobile/android/components/SessionStore.js
+++ b/mobile/android/components/SessionStore.js
@@ -909,26 +909,38 @@ SessionStore.prototype = {
     else
       throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG);
   },
 
   shouldRestore: function ss_shouldRestore() {
     return this._shouldRestore;
   },
 
-  restoreLastSession: function ss_restoreLastSession(aBringToFront) {
+  restoreLastSession: function ss_restoreLastSession(aBringToFront, aForceRestore) {
     let self = this;
     function notifyObservers(aMessage) {
       self._clearCache();
       Services.obs.notifyObservers(null, "sessionstore-windows-restored", aMessage || "");
     }
 
+    if (!aForceRestore) {
+      let maxCrashes = Services.prefs.getIntPref("browser.sessionstore.max_resumed_crashes");
+      let recentCrashes = Services.prefs.getIntPref("browser.sessionstore.recent_crashes") + 1;
+      Services.prefs.setIntPref("browser.sessionstore.recent_crashes", recentCrashes);
+      Services.prefs.savePrefFile(null);
+
+      if (recentCrashes > maxCrashes) {
+        notifyObservers("fail");
+        return;
+      }
+    }
+
     // The previous session data has already been renamed to the backup file
     if (!this._sessionFileBackup.exists()) {
-      notifyObservers("fail")
+      notifyObservers("fail");
       return;
     }
 
     try {
       let channel = NetUtil.newChannel(this._sessionFileBackup);
       channel.contentType = "application/json";
       NetUtil.asyncFetch(channel, function(aStream, aResult) {
         if (!Components.isSuccessCode(aResult)) {
--- a/widget/android/nsAppShell.cpp
+++ b/widget/android/nsAppShell.cpp
@@ -381,16 +381,22 @@ nsAppShell::ProcessNextNativeEvent(bool 
     }
 
     case AndroidGeckoEvent::ACTIVITY_PAUSING: {
         // We really want to send a notification like profile-before-change,
         // but profile-before-change ends up shutting some things down instead
         // of flushing data
         nsIPrefService* prefs = Preferences::GetService();
         if (prefs) {
+            // reset the crash loop state
+            nsCOMPtr<nsIPrefBranch> prefBranch;
+            prefs->GetBranch("browser.sessionstore.", getter_AddRefs(prefBranch));
+            if (prefBranch)
+                prefBranch->SetIntPref("recent_crashes", 0);
+
             prefs->SavePrefFile(nsnull);
         }
 
         break;
     }
 
     case AndroidGeckoEvent::ACTIVITY_START: {
         nsCOMPtr<nsIObserverService> obsServ =