From f3504d9241b2d9bb4e5d54fe15d307e309312360 Mon Sep 17 00:00:00 2001 From: Tim Taubert Date: Thu, 25 Sep 2014 23:26:41 +0200 Subject: [PATCH] Bug 1020831 - Make SessionStore.jsm and SessionFile.jsm share the same run state r=yoric --- browser/components/sessionstore/RunState.jsm | 66 +++++++++++++++++++ .../components/sessionstore/SessionFile.jsm | 4 +- .../components/sessionstore/SessionStore.jsm | 50 +++++--------- browser/components/sessionstore/moz.build | 1 + 4 files changed, 86 insertions(+), 35 deletions(-) create mode 100644 browser/components/sessionstore/RunState.jsm diff --git a/browser/components/sessionstore/RunState.jsm b/browser/components/sessionstore/RunState.jsm new file mode 100644 index 000000000000..4cb7070952fb --- /dev/null +++ b/browser/components/sessionstore/RunState.jsm @@ -0,0 +1,66 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +this.EXPORTED_SYMBOLS = ["RunState"]; + +const Cu = Components.utils; + +Cu.import("resource://gre/modules/Services.jsm", this); + +const STATE_STOPPED = 0; +const STATE_RUNNING = 1; +const STATE_QUITTING = 2; + +// We're initially stopped. +let state = STATE_STOPPED; + +function observer(subj, topic) { + Services.obs.removeObserver(observer, topic); + state = STATE_QUITTING; +} + +// Listen for when the application is quitting. +Services.obs.addObserver(observer, "quit-application-granted", false); + +/** + * This module keeps track of SessionStore's current run state. We will + * always start out at STATE_STOPPED. After the sessionw as read from disk and + * the initial browser window has loaded we switch to STATE_RUNNING. On the + * first notice that a browser shutdown was granted we switch to STATE_QUITTING. + */ +this.RunState = Object.freeze({ + // If we're stopped then SessionStore hasn't been initialized yet. As soon + // as the session is read from disk and the initial browser window has loaded + // the run state will change to STATE_RUNNING. + get isStopped() { + return state == STATE_STOPPED; + }, + + // STATE_RUNNING is our default mode of operation that we'll spend most of + // the time in. After the session was read from disk and the first browser + // window has loaded we remain running until the browser quits. + get isRunning() { + return state == STATE_RUNNING; + }, + + // We will enter STATE_QUITTING as soon as we receive notice that a browser + // shutdown was granted. SessionStore will use this information to prevent + // us from collecting partial information while the browser is shutting down + // as well as to allow a last single write to disk and block all writes after + // that. + get isQuitting() { + return state == STATE_QUITTING; + }, + + // Switch the run state to STATE_RUNNING. This must be called after the + // session was read from, the initial browser window has loaded and we're + // now ready to restore session data. + setRunning() { + if (this.isStopped) { + state = STATE_RUNNING; + } + } +}); diff --git a/browser/components/sessionstore/SessionFile.jsm b/browser/components/sessionstore/SessionFile.jsm index e1b753ae6992..36f42087b21e 100644 --- a/browser/components/sessionstore/SessionFile.jsm +++ b/browser/components/sessionstore/SessionFile.jsm @@ -38,6 +38,8 @@ Cu.import("resource://gre/modules/AsyncShutdown.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "console", "resource://gre/modules/devtools/Console.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "RunState", + "resource:///modules/sessionstore/RunState.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "TelemetryStopwatch", "resource://gre/modules/TelemetryStopwatch.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "Task", @@ -267,7 +269,7 @@ let SessionFileInternal = { } let isFinalWrite = false; - if (Services.startup.shuttingDown) { + if (RunState.isQuitting) { // If shutdown has started, we will want to stop receiving // write instructions. isFinalWrite = this._isClosed = true; diff --git a/browser/components/sessionstore/SessionStore.jsm b/browser/components/sessionstore/SessionStore.jsm index 5a5704a3f9a9..4d5069ecd65e 100644 --- a/browser/components/sessionstore/SessionStore.jsm +++ b/browser/components/sessionstore/SessionStore.jsm @@ -11,10 +11,6 @@ const Cc = Components.classes; const Ci = Components.interfaces; const Cr = Components.results; -const STATE_STOPPED = 0; -const STATE_RUNNING = 1; -const STATE_QUITTING = -1; - const TAB_STATE_NEEDS_RESTORE = 1; const TAB_STATE_RESTORING = 2; @@ -31,8 +27,7 @@ const MAX_CONCURRENT_TAB_RESTORES = 3; // global notifications observed const OBSERVING = [ "browser-window-before-show", "domwindowclosed", - "quit-application-requested", "quit-application-granted", - "browser-lastwindow-close-granted", + "quit-application-requested", "browser-lastwindow-close-granted", "quit-application", "browser:purge-session-history", "browser:purge-domain-data", "gather-telemetry", @@ -112,6 +107,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "GlobalState", "resource:///modules/sessionstore/GlobalState.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "PrivacyFilter", "resource:///modules/sessionstore/PrivacyFilter.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "RunState", + "resource:///modules/sessionstore/RunState.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "ScratchpadManager", "resource:///modules/devtools/scratchpad-manager.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "SessionSaver", @@ -288,9 +285,6 @@ let SessionStoreInternal = { Ci.nsISupportsWeakReference ]), - // set default load state - _loadState: STATE_STOPPED, - _globalState: new GlobalState(), // During the initial restore and setBrowserState calls tracks the number of @@ -472,7 +466,7 @@ let SessionStoreInternal = { // at this point, we've as good as resumed the session, so we can // clear the resume_session_once flag, if it's set - if (this._loadState != STATE_QUITTING && + if (!RunState.isQuitting && this._prefBranch.getBoolPref("sessionstore.resume_session_once")) this._prefBranch.setBoolPref("sessionstore.resume_session_once", false); @@ -531,9 +525,6 @@ let SessionStoreInternal = { case "quit-application-requested": this.onQuitApplicationRequested(); break; - case "quit-application-granted": - this.onQuitApplicationGranted(); - break; case "browser-lastwindow-close-granted": this.onLastWindowCloseGranted(); break; @@ -739,7 +730,7 @@ let SessionStoreInternal = { return; // ignore windows opened while shutting down - if (this._loadState == STATE_QUITTING) + if (RunState.isQuitting) return; // Assign the window a unique identifier we can use to reference @@ -764,8 +755,8 @@ let SessionStoreInternal = { this._windows[aWindow.__SSi].isPopup = true; // perform additional initialization when the first window is loading - if (this._loadState == STATE_STOPPED) { - this._loadState = STATE_RUNNING; + if (RunState.isStopped) { + RunState.setRunning(); SessionSaver.updateLastSaveTime(); // restore a crashed session resp. resume the last session if requested @@ -1008,7 +999,7 @@ let SessionStoreInternal = { let winData = this._windows[aWindow.__SSi]; // Collect window data only when *not* closed during shutdown. - if (this._loadState == STATE_RUNNING) { + if (RunState.isRunning) { // Flush all data queued in the content script before the window is gone. TabState.flushWindow(aWindow); @@ -1100,14 +1091,6 @@ let SessionStoreInternal = { DirtyWindows.clear(); }, - /** - * On quit application granted - */ - onQuitApplicationGranted: function ssi_onQuitApplicationGranted() { - // freeze the data at what we've got (ignoring closing windows) - this._loadState = STATE_QUITTING; - }, - /** * On last browser window close */ @@ -1141,7 +1124,6 @@ let SessionStoreInternal = { LastSession.clear(); } - this._loadState = STATE_QUITTING; // just to be sure this._uninit(); }, @@ -1153,7 +1135,7 @@ let SessionStoreInternal = { // If the browser is shutting down, simply return after clearing the // session data on disk as this notification fires after the // quit-application notification so the browser is about to exit. - if (this._loadState == STATE_QUITTING) + if (RunState.isQuitting) return; LastSession.clear(); let openWindows = {}; @@ -1179,7 +1161,7 @@ let SessionStoreInternal = { var win = this._getMostRecentBrowserWindow(); if (win) { win.setTimeout(() => SessionSaver.run(), 0); - } else if (this._loadState == STATE_RUNNING) { + } else if (RunState.isRunning) { SessionSaver.run(); } @@ -1237,7 +1219,7 @@ let SessionStoreInternal = { } } - if (this._loadState == STATE_RUNNING) { + if (RunState.isRunning) { SessionSaver.run(); } @@ -1368,7 +1350,7 @@ let SessionStoreInternal = { * Window reference */ onTabSelect: function ssi_onTabSelect(aWindow) { - if (this._loadState == STATE_RUNNING) { + if (RunState.isRunning) { this._windows[aWindow.__SSi].selected = aWindow.gBrowser.tabContainer.selectedIndex; let tab = aWindow.gBrowser.selectedTab; @@ -2033,7 +2015,7 @@ let SessionStoreInternal = { var activeWindow = this._getMostRecentBrowserWindow(); TelemetryStopwatch.start("FX_SESSION_RESTORE_COLLECT_ALL_WINDOWS_DATA_MS"); - if (this._loadState == STATE_RUNNING) { + if (RunState.isRunning) { // update the data for all windows with activities since the last save operation this._forEachBrowserWindow(function(aWindow) { if (!this._isWindowLoaded(aWindow)) // window data is still in _statesToRestore @@ -2090,7 +2072,7 @@ let SessionStoreInternal = { //XXXzpao We should do this for _restoreLastWindow == true, but that has // its own check for popups. c.f. bug 597619 if (nonPopupCount == 0 && lastClosedWindowsCopy.length > 0 && - this._loadState == STATE_QUITTING) { + RunState.isQuitting) { // prepend the last non-popup browser window, so that if the user loads more tabs // at startup we don't accidentally add them to a popup window do { @@ -2155,7 +2137,7 @@ let SessionStoreInternal = { if (!this._isWindowLoaded(aWindow)) return this._statesToRestore[aWindow.__SS_restoreID]; - if (this._loadState == STATE_RUNNING) { + if (RunState.isRunning) { this._collectWindowData(aWindow); } @@ -2637,7 +2619,7 @@ let SessionStoreInternal = { */ restoreNextTab: function ssi_restoreNextTab() { // If we call in here while quitting, we don't actually want to do anything - if (this._loadState == STATE_QUITTING) + if (RunState.isQuitting) return; // Don't exceed the maximum number of concurrent tab restores. diff --git a/browser/components/sessionstore/moz.build b/browser/components/sessionstore/moz.build index 863efecc376d..723a13489fb2 100644 --- a/browser/components/sessionstore/moz.build +++ b/browser/components/sessionstore/moz.build @@ -31,6 +31,7 @@ EXTRA_JS_MODULES.sessionstore = [ 'PrivacyFilter.jsm', 'PrivacyLevel.jsm', 'RecentlyClosedTabsAndWindowsMenuUtils.jsm', + 'RunState.jsm', 'SessionCookies.jsm', 'SessionFile.jsm', 'SessionHistory.jsm',