Bug 1279443 - Don't capture session state during startup before we've restored history. r=sebastian

When restoring tabs on startup, the Java UI creates tab stubs for the tabs from the previous session. The selected foreground tab then starts loading as soon as Gecko is up and running. Meanwhile, the session store gets initialised, too and starts restoring history and other things for that tab.

After history has been restored for an active tab, the session store reloads the current history entry, however by that time, depending on device speed, page size and how many other tabs the session store has to process during startup, the initial page load might have progressed far enough to have already triggered various events monitored by the session store, e.g. "pageshow".

If those events arrive before tab restoring has finished, the session store will attempt to capture that tab's state, which will overwrite the values stored from the previous session. Once the page is then reloaded for restoring, wrong values (e.g. form data, scroll position, zoom level) might then be restored.

Therefore, we now abort any attempts to capture a tab's state
- for all tabs until the "sessionstore-windows-restored" notification has been received as a signal that the initial session restore during startup has finished
- for the restored foreground tab until the location change notification is received after reloading

MozReview-Commit-ID: HbhXcEUnRXQ

--HG--
extra : transplant_source : h%2C%DA%27%28%F0%9F%8F%15-%21F/b%18%B5%DF%F4.%BE
This commit is contained in:
Jan Henning 2016-06-29 18:24:13 +02:00
parent a8c9dbb72e
commit 14cc31c7f4

View File

@ -82,6 +82,7 @@ SessionStore.prototype = {
this._sessionFileBackup.append("sessionstore.bak");
this._loadState = STATE_STOPPED;
this._startupRestoreFinished = false;
this._interval = Services.prefs.getIntPref("browser.sessionstore.interval");
this._maxTabsUndo = Services.prefs.getIntPref("browser.sessionstore.max_tabs_undo");
@ -214,6 +215,10 @@ SessionStore.prototype = {
selected: true
});
}
// Normally, _restoreWindow() will have set this to true already,
// but we want to make sure it's set even in case of a restore failure.
this._startupRestoreFinished = true;
log("startupRestoreFinished = true (through notification)");
}.bind(this)
};
Services.obs.addObserver(restoreCleanup, "sessionstore-windows-restored", false);
@ -223,12 +228,20 @@ SessionStore.prototype = {
this.restoreLastSession(data.sessionString);
} else {
// Not doing a restore; just send restore message
this._startupRestoreFinished = true;
log("startupRestoreFinished = true");
Services.obs.notifyObservers(null, "sessionstore-windows-restored", "");
}
break;
}
case "Session:NotifyLocationChange": {
let browser = aSubject;
if (browser.__SS_restoreReloadPending && this._startupRestoreFinished) {
delete browser.__SS_restoreReloadPending;
log("remove restoreReloadPending");
}
if (browser.__SS_restoreDataOnLocationChange) {
delete browser.__SS_restoreDataOnLocationChange;
this._restoreZoom(browser.__SS_data.scrolldata, browser);
@ -535,8 +548,9 @@ SessionStore.prototype = {
},
onTabLoad: function ss_onTabLoad(aWindow, aBrowser) {
// If this browser is being restored, skip any session save activity
if (aBrowser.__SS_restore) {
// If this browser belongs to a zombie tab or the initial restore hasn't yet finished,
// skip any session save activity.
if (aBrowser.__SS_restore || !this._startupRestoreFinished || aBrowser.__SS_restoreReloadPending) {
return;
}
@ -630,8 +644,9 @@ SessionStore.prototype = {
},
onTabInput: function ss_onTabInput(aWindow, aBrowser) {
// If this browser is being restored, skip any session save activity
if (aBrowser.__SS_restore) {
// If this browser belongs to a zombie tab or the initial restore hasn't yet finished,
// skip any session save activity.
if (aBrowser.__SS_restore || !this._startupRestoreFinished || aBrowser.__SS_restoreReloadPending) {
return;
}
@ -689,8 +704,9 @@ SessionStore.prototype = {
log("onTabScroll() clearing pending timeout");
}
// If this browser is being restored, skip any session save activity.
if (aBrowser.__SS_restore) {
// If this browser belongs to a zombie tab or the initial restore hasn't yet finished,
// skip any session save activity.
if (aBrowser.__SS_restore || !this._startupRestoreFinished || aBrowser.__SS_restoreReloadPending) {
return;
}
@ -1472,6 +1488,13 @@ SessionStore.prototype = {
if (window.BrowserApp.selectedTab == tab) {
this._restoreTab(tabData, tab.browser);
// We can now lift the general ban on tab data capturing,
// but we still need to protect the foreground tab until we're
// sure it's actually reloading after history restoring has finished.
tab.browser.__SS_restoreReloadPending = true;
this._startupRestoreFinished = true;
log("startupRestoreFinished = true");
delete tab.browser.__SS_restore;
tab.browser.removeAttribute("pending");
} else {