Bug 1044556 - Part 1 - Notify the session store about tab zombifications. r=sebastian
The session store relies on a few event listeners to track the history and life cycle of a tab. Under memory pressure, background tabs are zombified in order to reduce our memory usage. This involves destroying the original tab object and then recreating it as a delay loaded tab.
As the session store is never told about this, it will keep the event listeners for the old tab objects - which have now been destroyed - alive and won't receive any future events for the new tab objects. This means that once a zombification has been triggered, the session history for those tabs will become effectively frozen, so after the next zombification or a session restore, the tab will reload the wrong page.
Therefore this patch introduces two new events which are sent during the tab zombification process and allow the session store to detach its event listeners from the old tab object before it is going to be destroyed and subsequently reattach its listeners to the new tab object.
MozReview-Commit-ID: 6xZtsCNZbQY
--- a/mobile/android/chrome/content/MemoryObserver.js
+++ b/mobile/android/chrome/content/MemoryObserver.js
@@ -49,31 +49,41 @@ var MemoryObserver = {
if (tab.playingAudio) {
Messaging.sendRequest({
type: "Tab:AudioPlayingChange",
tabID: tab.id,
isAudioPlaying: false
});
}
+ // Notify the session store that the original tab object is going to be destroyed
+ let evt = document.createEvent("UIEvents");
+ evt.initUIEvent("TabPreZombify", true, false, window, null);
+ browser.dispatchEvent(evt);
+
// We need this data to correctly create and position the new browser
// If this browser is already a zombie, fallback to the session data
let currentURL = browser.__SS_restore ? data.entries[0].url : browser.currentURI.spec;
let sibling = browser.nextSibling;
let isPrivate = PrivateBrowsingUtils.isBrowserPrivate(browser);
tab.destroy();
tab.create(currentURL, { sibling: sibling, zombifying: true, delayLoad: true, isPrivate: isPrivate });
// Reattach session store data and flag this browser so it is restored on select
browser = tab.browser;
browser.__SS_data = data;
browser.__SS_extdata = extra;
browser.__SS_restore = true;
browser.setAttribute("pending", "true");
+
+ // Notify the session store to reattach its listeners to the new tab object
+ evt = document.createEvent("UIEvents");
+ evt.initUIEvent("TabPostZombify", true, false, window, null);
+ browser.dispatchEvent(evt);
},
gc: function() {
window.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils).garbageCollect();
Cu.forceGC();
},
dumpMemoryStats: function(aLabel) {
--- a/mobile/android/components/SessionStore.js
+++ b/mobile/android/components/SessionStore.js
@@ -208,16 +208,26 @@ SessionStore.prototype = {
break;
}
case "TabClose": {
let browser = aEvent.target;
this.onTabClose(window, browser, aEvent.detail);
this.onTabRemove(window, browser);
break;
}
+ case "TabPreZombify": {
+ let browser = aEvent.target;
+ this.onTabRemove(window, browser, true);
+ break;
+ }
+ case "TabPostZombify": {
+ let browser = aEvent.target;
+ this.onTabAdd(window, browser, true);
+ break;
+ }
case "TabSelect": {
let browser = aEvent.target;
this.onTabSelect(window, browser);
break;
}
case "DOMTitleChanged": {
let browser = aEvent.currentTarget;
@@ -272,32 +282,36 @@ SessionStore.prototype = {
this._lastSaveTime = Date.now();
}
// Add tab change listeners to all already existing tabs
let tabs = aWindow.BrowserApp.tabs;
for (let i = 0; i < tabs.length; i++)
this.onTabAdd(aWindow, tabs[i].browser, true);
- // Notification of tab add/remove/selection
+ // Notification of tab add/remove/selection/zombification
let browsers = aWindow.document.getElementById("browsers");
browsers.addEventListener("TabOpen", this, true);
browsers.addEventListener("TabClose", this, true);
browsers.addEventListener("TabSelect", this, true);
+ browsers.addEventListener("TabPreZombify", this, true);
+ browsers.addEventListener("TabPostZombify", this, true);
},
onWindowClose: function ss_onWindowClose(aWindow) {
// Ignore windows not tracked by SessionStore
if (!aWindow.__SSID || !this._windows[aWindow.__SSID])
return;
let browsers = aWindow.document.getElementById("browsers");
browsers.removeEventListener("TabOpen", this, true);
browsers.removeEventListener("TabClose", this, true);
browsers.removeEventListener("TabSelect", this, true);
+ browsers.removeEventListener("TabPreZombify", this, true);
+ browsers.removeEventListener("TabPostZombify", this, true);
if (this._loadState == STATE_RUNNING) {
// Update all window data for a last time
this._collectWindowData(aWindow);
// Clear this window from the list
delete this._windows[aWindow.__SSID];