Bug 701092 - Limit session restore attempts. r=mfinkle a=akeybl
authorBrian Nicholson <bnicholson@mozilla.com>
Fri, 27 Jan 2012 22:04:54 -0800
changeset 85276 8a81092f109dd66ba9cd1bbf0372a49f7a9c3f7c
parent 85275 de24a5e2b9eeffac188cc0fffd5b915b99df94c0
child 85277 a4b49d0d8e129c72bb14effb780116dbb952fdec
push id549
push userblassey@mozilla.com
push dateMon, 06 Feb 2012 19:46:39 +0000
treeherdermozilla-beta@4bfd54f405de [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmfinkle, akeybl
bugs701092
milestone11.0
Bug 701092 - Limit session restore attempts. r=mfinkle a=akeybl
mobile/android/app/mobile.js
mobile/android/chrome/content/browser.js
mobile/android/components/SessionStore.idl
mobile/android/components/SessionStore.js
widget/src/android/nsAppShell.cpp
--- a/mobile/android/app/mobile.js
+++ b/mobile/android/app/mobile.js
@@ -142,16 +142,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
@@ -261,62 +261,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
@@ -910,26 +910,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/src/android/nsAppShell.cpp
+++ b/widget/src/android/nsAppShell.cpp
@@ -380,16 +380,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 =