Bug 965137 - Replace SessionStore pageshow listener with DOMTitleChanged listener. r=mfinkle
authorBrian Nicholson <bnicholson@mozilla.com>
Wed, 05 Feb 2014 23:47:51 -0800
changeset 167184 c08cc49abbe6b1fdffe23bcafe3a3e56cd6e72bc
parent 167183 bf45888656ad3f94fa4c31e9a903d5a3a98bd2d5
child 167185 71740219ddf9ca6e8ae0c4d56d4aa8c38b21e2b7
child 167244 f8ad3611031bd7f7788f981ad2e16cd4597fac16
push id26160
push usercbook@mozilla.com
push dateThu, 06 Feb 2014 11:51:41 +0000
treeherdermozilla-central@71740219ddf9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmfinkle
bugs965137
milestone30.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 965137 - Replace SessionStore pageshow listener with DOMTitleChanged listener. r=mfinkle
mobile/android/base/tests/SessionTest.java
mobile/android/base/tests/testSessionOOMSave.java
mobile/android/components/SessionStore.js
--- a/mobile/android/base/tests/SessionTest.java
+++ b/mobile/android/base/tests/SessionTest.java
@@ -373,16 +373,20 @@ public abstract class SessionTest extend
         try {
             writeFile(new File(mProfile, filename), data);
         } catch (IOException e) {
             mAsserter.ok(false, "Error writing to " + filename, getStackTraceString(e));
         }
     }
 
     private String readFile(File target) throws IOException {
+        if (!target.exists()) {
+            return null;
+        }
+
         FileReader fr = new FileReader(target);
         try {
             StringBuffer sb = new StringBuffer();
             char[] buf = new char[8192];
             int read = fr.read(buf);
             while (read >= 0) {
                 sb.append(buf, 0, read);
                 read = fr.read(buf);
--- a/mobile/android/base/tests/testSessionOOMSave.java
+++ b/mobile/android/base/tests/testSessionOOMSave.java
@@ -58,16 +58,21 @@ public class testSessionOOMSave extends 
         public VerifyJSONCondition(Session session) {
             mSession = session;
         }
 
         @Override
         public boolean isSatisfied() {
             try {
                 String sessionString = readProfileFile("sessionstore.js");
+                if (sessionString == null) {
+                    mLastException = new AssertException("Could not read sessionstore.js");
+                    return false;
+                }
+
                 verifySessionJSON(mSession, sessionString, mAsserter);
             } catch (AssertException e) {
                 mLastException = e;
                 return false;
             }
             return true;
         }
 
--- a/mobile/android/components/SessionStore.js
+++ b/mobile/android/components/SessionStore.js
@@ -112,16 +112,17 @@ SessionStore.prototype = {
       case "timer-callback":
         // Timer call back for delayed saving
         this._saveTimer = null;
         if (this._pendingWrite) {
           this.saveState();
         }
         break;
       case "Session:Restore": {
+        Services.obs.removeObserver(this, "Session:Restore");
         if (aData) {
           // Be ready to handle any restore failures by making sure we have a valid tab opened
           let window = Services.wm.getMostRecentWindow("navigator:browser");
           let restoreCleanup = {
             observe: function (aSubject, aTopic, aData) {
               Services.obs.removeObserver(restoreCleanup, "sessionstore-windows-restored");
 
               if (window.BrowserApp.tabs.length == 0) {
@@ -171,21 +172,25 @@ SessionStore.prototype = {
         this.onTabRemove(window, browser);
         break;
       }
       case "TabSelect": {
         let browser = aEvent.target;
         this.onTabSelect(window, browser);
         break;
       }
-      case "pageshow": {
-        let browser = aEvent.currentTarget;
-        // Top-level changes only
-        if (aEvent.originalTarget == browser.contentDocument)
-          this.onTabLoad(window, browser, aEvent.persisted);
+      case "DOMTitleChanged": {
+        let browser = Services.wm.getMostRecentWindow("navigator:browser")
+                                 .BrowserApp
+                                 .getBrowserForDocument(aEvent.target);
+        // Use DOMTitleChanged to detect page loads over alternatives.
+        // onLocationChange happens too early, so we don't have the page title
+        // yet; pageshow happens too late, so we could lose session data if the
+        // browser were killed.
+        this.onTabLoad(window, browser);
         break;
       }
     }
   },
 
   onWindowOpen: function ss_onWindowOpen(aWindow) {
     // Return if window has already been initialized
     if (aWindow && aWindow.__SSID && this._windows[aWindow.__SSID])
@@ -210,27 +215,29 @@ SessionStore.prototype = {
     for (let i = 0; i < tabs.length; i++)
       this.onTabAdd(aWindow, tabs[i].browser, true);
 
     // Notification of tab add/remove/selection
     let browsers = aWindow.document.getElementById("browsers");
     browsers.addEventListener("TabOpen", this, true);
     browsers.addEventListener("TabClose", this, true);
     browsers.addEventListener("TabSelect", this, true);
+    browsers.addEventListener("DOMTitleChanged", 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("DOMTitleChanged", 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];
 
@@ -241,25 +248,22 @@ SessionStore.prototype = {
     let tabs = aWindow.BrowserApp.tabs;
     for (let i = 0; i < tabs.length; i++)
       this.onTabRemove(aWindow, tabs[i].browser, true);
 
     delete aWindow.__SSID;
   },
 
   onTabAdd: function ss_onTabAdd(aWindow, aBrowser, aNoNotification) {
-    aBrowser.addEventListener("pageshow", this, true);
     if (!aNoNotification)
       this.saveStateDelayed();
     this._updateCrashReportURL(aWindow);
   },
 
   onTabRemove: function ss_onTabRemove(aWindow, aBrowser, aNoNotification) {
-    aBrowser.removeEventListener("pageshow", this, true);
-
     // If this browser is being restored, skip any session save activity
     if (aBrowser.__SS_restore)
       return;
 
     delete aBrowser.__SS_data;
 
     if (!aNoNotification)
       this.saveStateDelayed();
@@ -277,53 +281,47 @@ SessionStore.prototype = {
 
       this._windows[aWindow.__SSID].closedTabs.unshift(data);
       let length = this._windows[aWindow.__SSID].closedTabs.length;
       if (length > this._maxTabsUndo)
         this._windows[aWindow.__SSID].closedTabs.splice(this._maxTabsUndo, length - this._maxTabsUndo);
     }
   },
 
-  onTabLoad: function ss_onTabLoad(aWindow, aBrowser, aPersisted) {
+  onTabLoad: function ss_onTabLoad(aWindow, aBrowser) {
     // If this browser is being restored, skip any session save activity
     if (aBrowser.__SS_restore)
       return;
 
     // Ignore a transient "about:blank"
     if (!aBrowser.canGoBack && aBrowser.currentURI.spec == "about:blank")
       return;
 
     let history = aBrowser.sessionHistory;
 
-    if (aPersisted && aBrowser.__SS_data) {
-      // Loading from the cache; just update the index
-      aBrowser.__SS_data.index = history.index + 1;
-      this.saveStateDelayed();
-    } else {
-      // Serialize the tab data
-      let entries = [];
-      let index = history.index + 1;
-      for (let i = 0; i < history.count; i++) {
-        let historyEntry = history.getEntryAtIndex(i, false);
-        // Don't try to restore wyciwyg URLs
-        if (historyEntry.URI.schemeIs("wyciwyg")) {
-          // Adjust the index to account for skipped history entries
-          if (i <= history.index)
-            index--;
-          continue;
-        }
-        let entry = this._serializeHistoryEntry(historyEntry);
-        entries.push(entry);
+    // Serialize the tab data
+    let entries = [];
+    let index = history.index + 1;
+    for (let i = 0; i < history.count; i++) {
+      let historyEntry = history.getEntryAtIndex(i, false);
+      // Don't try to restore wyciwyg URLs
+      if (historyEntry.URI.schemeIs("wyciwyg")) {
+        // Adjust the index to account for skipped history entries
+        if (i <= history.index)
+          index--;
+        continue;
       }
-      let data = { entries: entries, index: index };
+      let entry = this._serializeHistoryEntry(historyEntry);
+      entries.push(entry);
+    }
+    let data = { entries: entries, index: index };
 
-      delete aBrowser.__SS_data;
-      this._collectTabData(aWindow, aBrowser, data);
-      this.saveState();
-    }
+    delete aBrowser.__SS_data;
+    this._collectTabData(aWindow, aBrowser, data);
+    this.saveStateDelayed();
 
     this._updateCrashReportURL(aWindow);
   },
 
   onTabSelect: function ss_onTabSelect(aWindow, aBrowser) {
     if (this._loadState != STATE_RUNNING)
       return;