Bug 1145942 - Use the frame message manager to revive crashed tabs upon navigation r=billm
authorTim Taubert <ttaubert@mozilla.com>
Sat, 21 Mar 2015 08:20:28 +0100
changeset 264162 58d55fdfd89ddb8ea2711e70436912920b841392
parent 264161 66e17a44a01cf30f248cb725ca156ac6c6c84936
child 264163 2e22440310321d890737f32af5ff31549ec70c6d
child 264239 94fa5538015cd37e500eaa4fa83349fc0de3f0b2
push id4718
push userraliiev@mozilla.com
push dateMon, 11 May 2015 18:39:53 +0000
treeherdermozilla-beta@c20c4ef55f08 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbillm
bugs1145942
milestone39.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 1145942 - Use the frame message manager to revive crashed tabs upon navigation r=billm
browser/components/sessionstore/SessionStore.jsm
browser/components/sessionstore/content/content-sessionStore.js
--- a/browser/components/sessionstore/SessionStore.jsm
+++ b/browser/components/sessionstore/SessionStore.jsm
@@ -40,17 +40,17 @@ const WINDOW_ATTRIBUTES = ["width", "hei
 
 // Hideable window features to (re)store
 // Restored in restoreWindowFeatures()
 const WINDOW_HIDEABLE_FEATURES = [
   "menubar", "toolbar", "locationbar", "personalbar", "statusbar", "scrollbars"
 ];
 
 // Messages that will be received via the Frame Message Manager.
-const FMM_MESSAGES = [
+const MESSAGES = [
   // The content script gives us a reference to an object that performs
   // synchronous collection of session data.
   "SessionStore:setupSyncHandler",
 
   // The content script sends us data that has been invalidated and needs to
   // be saved to disk.
   "SessionStore:update",
 
@@ -65,37 +65,39 @@ const FMM_MESSAGES = [
   // consider restoring another tab in the queue. The document has
   // been restored, and forms have been filled. We trigger
   // SSTabRestored at this time.
   "SessionStore:restoreTabContentComplete",
 
   // A tab that is being restored was reloaded. We call restoreTabContent to
   // finish restoring it right away.
   "SessionStore:reloadPendingTab",
+
+  // A crashed tab was revived by navigating to a different page. Remove its
+  // browser from the list of crashed browsers to stop ignoring its messages.
+  "SessionStore:crashedTabRevived",
 ];
 
 // The list of messages we accept from <xul:browser>s that have no tab
 // assigned. Those are for example the ones that preload about:newtab pages.
-const FMM_NOTAB_MESSAGES = new Set([
+const NOTAB_MESSAGES = new Set([
   // For a description see above.
   "SessionStore:setupSyncHandler",
 
   // For a description see above.
   "SessionStore:update",
 ]);
 
-// Messages that will be received via the Parent Process Message Manager.
-const PPMM_MESSAGES = [
-  // A tab is being revived from the crashed state. The sender of this
-  // message should actually be running in the parent process, since this
-  // will be the crashed tab interface. We use the Child and Parent Process
-  // Message Managers because the message is sent during framescript unload
-  // when the Frame Message Manager is not available.
-  "SessionStore:RemoteTabRevived",
-];
+// The list of messages we want to receive even during the short period after a
+// frame has been removed from the DOM and before its frame script has finished
+// unloading.
+const CLOSED_MESSAGES = new Set([
+  // For a description see above.
+  "SessionStore:crashedTabRevived",
+]);
 
 // These are tab events that we listen to.
 const TAB_EVENTS = [
   "TabOpen", "TabClose", "TabSelect", "TabShow", "TabHide", "TabPinned",
   "TabUnpinned"
 ];
 
 // The number of milliseconds in a day
@@ -418,18 +420,16 @@ let SessionStoreInternal = {
       throw new Error("SessionStore.init() must only be called once!");
     }
 
     TelemetryTimestamps.add("sessionRestoreInitialized");
     OBSERVING.forEach(function(aTopic) {
       Services.obs.addObserver(this, aTopic, true);
     }, this);
 
-    PPMM_MESSAGES.forEach(msg => ppmm.addMessageListener(msg, this));
-
     this._initPrefs();
     this._initialized = true;
   },
 
   /**
    * Initialize the session using the state provided by SessionStartup
    */
   initSession: function () {
@@ -549,18 +549,16 @@ let SessionStoreInternal = {
       SessionSaver.run();
     }
 
     // clear out priority queue in case it's still holding refs
     TabRestoreQueue.reset();
 
     // Make sure to cancel pending saves.
     SessionSaver.cancel();
-
-    PPMM_MESSAGES.forEach(msg => ppmm.removeMessageListener(msg, this));
   },
 
   /**
    * Handle notifications
    */
   observe: function ssi_observe(aSubject, aTopic, aData) {
     switch (aTopic) {
       case "browser-window-before-show": // catch new windows
@@ -597,31 +595,25 @@ let SessionStoreInternal = {
   },
 
   /**
    * This method handles incoming messages sent by the session store content
    * script via the Frame Message Manager or Parent Process Message Manager,
    * and thus enables communication with OOP tabs.
    */
   receiveMessage(aMessage) {
-    // We'll deal with any Parent Process Message Manager messages first...
-    if (aMessage.name == "SessionStore:RemoteTabRevived") {
-      this._crashedBrowsers.delete(aMessage.objects.browser.permanentKey);
-      return;
-    }
-
     // If we got here, that means we're dealing with a frame message
     // manager message, so the target will be a <xul:browser>.
     var browser = aMessage.target;
     var win = browser.ownerDocument.defaultView;
     let tab = win.gBrowser.getTabForBrowser(browser);
 
     // Ensure we receive only specific messages from <xul:browser>s that
     // have no tab assigned, e.g. the ones that preload about:newtab pages.
-    if (!tab && !FMM_NOTAB_MESSAGES.has(aMessage.name)) {
+    if (!tab && !NOTAB_MESSAGES.has(aMessage.name)) {
       throw new Error(`received unexpected message '${aMessage.name}' ` +
                       `from a browser that has no tab`);
     }
 
     switch (aMessage.name) {
       case "SessionStore:setupSyncHandler":
         TabState.setSyncHandler(browser, aMessage.objects.handler);
         break;
@@ -704,16 +696,19 @@ let SessionStoreInternal = {
         break;
       case "SessionStore:reloadPendingTab":
         if (this.isCurrentEpoch(browser, aMessage.data.epoch)) {
           if (browser.__SS_restoreState == TAB_STATE_NEEDS_RESTORE) {
             this.restoreTabContent(tab);
           }
         }
         break;
+      case "SessionStore:crashedTabRevived":
+        this._crashedBrowsers.delete(browser.permanentKey);
+        break;
       default:
         throw new Error(`received unknown message '${aMessage.name}'`);
         break;
     }
   },
 
   /**
    * Record telemetry measurements stored in an object.
@@ -794,17 +789,20 @@ let SessionStoreInternal = {
     if (RunState.isQuitting)
       return;
 
     // Assign the window a unique identifier we can use to reference
     // internal data about the window.
     aWindow.__SSi = this._generateWindowID();
 
     let mm = aWindow.getGroupMessageManager("browsers");
-    FMM_MESSAGES.forEach(msg => mm.addMessageListener(msg, this));
+    MESSAGES.forEach(msg => {
+      let listenWhenClosed = CLOSED_MESSAGES.has(msg);
+      mm.addMessageListener(msg, this, listenWhenClosed);
+    });
 
     // Load the frame script after registering listeners.
     mm.loadFrameScript("chrome://browser/content/content-sessionStore.js", true);
 
     // and create its data object
     this._windows[aWindow.__SSi] = { tabs: [], selected: 0, _closedTabs: [], busy: false };
 
     let isPrivateWindow = false;
@@ -1123,17 +1121,17 @@ let SessionStoreInternal = {
     for (let i = 0; i < tabbrowser.tabs.length; i++) {
       this.onTabRemove(aWindow, tabbrowser.tabs[i], true);
     }
 
     // Cache the window state until it is completely gone.
     DyingWindowCache.set(aWindow, winData);
 
     let mm = aWindow.getGroupMessageManager("browsers");
-    FMM_MESSAGES.forEach(msg => mm.removeMessageListener(msg, this));
+    MESSAGES.forEach(msg => mm.removeMessageListener(msg, this));
 
     delete aWindow.__SSi;
   },
 
   /**
    * On quit application requested
    */
   onQuitApplicationRequested: function ssi_onQuitApplicationRequested() {
--- a/browser/components/sessionstore/content/content-sessionStore.js
+++ b/browser/components/sessionstore/content/content-sessionStore.js
@@ -744,22 +744,18 @@ function handleRevivedTab() {
     if (Services.appinfo.processType != Services.appinfo.PROCESS_TYPE_DEFAULT) {
       // Sanity check - we'd better be loading this in a non-remote browser.
       throw new Error("We seem to be navigating away from about:tabcrashed in " +
                       "a non-remote browser. This should really never happen.");
     }
 
     removeEventListener("pagehide", handleRevivedTab);
 
-    // We can't send a message using the frame message manager because by
-    // the time we reach the unload event handler, it's "too late", and messages
-    // won't be sent or received. The child-process message manager works though,
-    // despite the fact that we're really running in the parent process.
-    let browser = docShell.chromeEventHandler;
-    cpmm.sendAsyncMessage("SessionStore:RemoteTabRevived", null, {browser: browser});
+    // Notify the parent.
+    sendAsyncMessage("SessionStore:crashedTabRevived");
   }
 }
 
 // If we're browsing from the tab crashed UI to a blacklisted URI that keeps
 // this browser non-remote, we'll handle that in a pagehide event.
 addEventListener("pagehide", handleRevivedTab);
 
 addEventListener("unload", () => {