Bug 1190627 - Part 3 - Reduce session store save delays when in background. r=margaret draft
authorJan Henning <jh+bugzilla@buttercookie.de>
Sun, 17 Apr 2016 22:06:06 +0200
changeset 376093 f30c8aab86bb5b55019fd6ea7958f51e51563112
parent 376092 96b82f4a2304e118f47ad0d1bf6b739898b9b7c8
child 376094 8de568dd9e25fb3cae4a0773978f7074cbf4584d
push id20502
push usermozilla@buttercookie.de
push dateTue, 07 Jun 2016 11:58:37 +0000
reviewersmargaret
bugs1190627
milestone50.0a1
Bug 1190627 - Part 3 - Reduce session store save delays when in background. r=margaret When we are backgrounded and Android's onPause() handler runs, we try to synchronously flush out any pending session store to storage. If however some tab events (e.g. tab closing) have been dispatched shortly before the application backgrounding, it is possible that they'll arrive at the session store after the "application-background" event. In this case, we need to process and write them to storage as fast as possible, as we can be killed at any moment now. Therefore the delay between successive writes is completely abolished while the application is in background. The minimum delay between a call to saveStateDelayed() and a write operation however is not completely eliminated and instead only reduced to 200 ms, so as to allow for closely following tab events (e.g. closing a tab involves both a TabSelect and TabClose event) to be batched together in one write operation. MozReview-Commit-ID: I8q7z4kll7O
mobile/android/components/SessionStore.js
--- a/mobile/android/components/SessionStore.js
+++ b/mobile/android/components/SessionStore.js
@@ -42,29 +42,32 @@ const STATE_RUNNING = 1;
 
 const PRIVACY_NONE = 0;
 const PRIVACY_ENCRYPTED = 1;
 const PRIVACY_FULL = 2;
 
 const PREFS_RESTORE_FROM_CRASH = "browser.sessionstore.resume_from_crash";
 const PREFS_MAX_CRASH_RESUMES = "browser.sessionstore.max_resumed_crashes";
 
+const MINIMUM_SAVE_DELAY = 2000;
+
 function SessionStore() { }
 
 SessionStore.prototype = {
   classID: Components.ID("{8c1f07d6-cba3-4226-a315-8bd43d67d032}"),
 
   QueryInterface: XPCOMUtils.generateQI([Ci.nsISessionStore,
                                          Ci.nsIDOMEventListener,
                                          Ci.nsIObserver,
                                          Ci.nsISupportsWeakReference]),
 
   _windows: {},
   _lastSaveTime: 0,
   _interval: 10000,
+  _minSaveDelay: MINIMUM_SAVE_DELAY,
   _maxTabsUndo: 5,
   _scrollSavePending: null,
   _pendingWrite: 0,
   _writeInProgress: false,
   _deferredWrite: {},
 
   // The index where the most recently closed tab was in the tabs array
   // when it was closed.
@@ -114,16 +117,17 @@ SessionStore.prototype = {
       case "app-startup":
         observerService.addObserver(this, "final-ui-startup", true);
         observerService.addObserver(this, "domwindowopened", true);
         observerService.addObserver(this, "domwindowclosed", true);
         observerService.addObserver(this, "browser:purge-session-history", true);
         observerService.addObserver(this, "Session:Restore", true);
         observerService.addObserver(this, "Session:NotifyLocationChange", true);
         observerService.addObserver(this, "application-background", true);
+        observerService.addObserver(this, "application-foreground", true);
         observerService.addObserver(this, "ClosedTabs:StartNotifications", true);
         observerService.addObserver(this, "ClosedTabs:StopNotifications", true);
         observerService.addObserver(this, "last-pb-context-exited", true);
         observerService.addObserver(this, "Session:RestoreRecentTabs", true);
         observerService.addObserver(this, "Tabs:OpenMultiple", true);
         break;
       case "final-ui-startup":
         observerService.removeObserver(this, "final-ui-startup");
@@ -215,18 +219,28 @@ SessionStore.prototype = {
         break;
       }
       case "application-background":
         // We receive this notification when Android's onPause callback is
         // executed. After onPause, the application may be terminated at any
         // point without notice; therefore, we must synchronously write out any
         // pending save state to ensure that this data does not get lost.
         log("application-background");
+        // Tab events dispatched immediately before the application was backgrounded
+        // might actually arrive after this point, therefore save them without delay.
+        this._interval = 0;
+        this._minSaveDelay = 200; // Small delay to allow successive tab events to be batched together.
         this.flushPendingState();
         break;
+      case "application-foreground":
+        // Reset minimum interval between session store writes back to default.
+        log("application-foreground");
+        this._interval = Services.prefs.getIntPref("browser.sessionstore.interval");
+        this._minSaveDelay = MINIMUM_SAVE_DELAY;
+        break;
       case "ClosedTabs:StartNotifications":
         this._notifyClosedTabs = true;
         log("ClosedTabs:StartNotifications");
         this._sendClosedTabsToJava(Services.wm.getMostRecentWindow("navigator:browser"));
         break;
       case "ClosedTabs:StopNotifications":
         this._notifyClosedTabs = false;
         log("ClosedTabs:StopNotifications");
@@ -742,20 +756,20 @@ SessionStore.prototype = {
     viewportInfo.autoSize = autoSize.value;
 
     return viewportInfo;
   },
 
   saveStateDelayed: function ss_saveStateDelayed() {
     if (!this._saveTimer) {
       // Interval until the next disk operation is allowed
-      let minimalDelay = this._lastSaveTime + this._interval - Date.now();
+      let currentDelay = this._lastSaveTime + this._interval - Date.now();
 
       // If we have to wait, set a timer, otherwise saveState directly
-      let delay = Math.max(minimalDelay, 2000);
+      let delay = Math.max(currentDelay, this._minSaveDelay);
       if (delay > 0) {
         this._pendingWrite++;
         this._saveTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
         this._saveTimer.init(this, delay, Ci.nsITimer.TYPE_ONE_SHOT);
         log("saveStateDelayed() timer delay = " + delay +
              ", incrementing _pendingWrite to " + this._pendingWrite);
       } else {
         log("saveStateDelayed() no delay");