Bug 850372 - Delete session store backup during process suspend so that termination-from-suspended-state is treated as a normal shutdown. r=mbrubeck, a=lsblakk
authorTim Abraldes <tabraldes@mozilla.com>
Thu, 19 Dec 2013 11:32:12 -0500
changeset 175576 2798a7fdcf67f2c12c8028ae0025e6070492d9a2
parent 175575 3243eff810258f8cbedf2e48130c0e628bb8e33a
child 175577 f641a07ad54c5e4e851f46f6e128dcd2e7330c06
push id445
push userffxbld
push dateMon, 10 Mar 2014 22:05:19 +0000
treeherdermozilla-release@dc38b741b04e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmbrubeck, lsblakk
bugs850372
milestone28.0a2
Bug 850372 - Delete session store backup during process suspend so that termination-from-suspended-state is treated as a normal shutdown. r=mbrubeck, a=lsblakk
browser/metro/components/SessionStore.js
widget/nsIWinMetroUtils.idl
widget/windows/winrt/FrameworkView.cpp
widget/windows/winrt/FrameworkView.h
widget/windows/winrt/nsWinMetroUtils.cpp
--- a/browser/metro/components/SessionStore.js
+++ b/browser/metro/components/SessionStore.js
@@ -57,34 +57,74 @@ SessionStore.prototype = {
     this._sessionCache = this._sessionFile.clone();
     this._sessionFile.append("sessionstore.js");
     this._sessionFileBackup.append("sessionstore.bak");
     this._sessionCache.append("sessionstoreCache");
 
     this._loadState = STATE_STOPPED;
 
     try {
+      let shutdownWasUnclean = false;
+
       if (this._sessionFileBackup.exists()) {
-        this._shouldRestore = true;
         this._sessionFileBackup.remove(false);
+        shutdownWasUnclean = true;
       }
 
       if (this._sessionFile.exists()) {
-        // Disable crash recovery if we have exceeded the timeout
-        this._lastSessionTime = this._sessionFile.lastModifiedTime;
-        let delta = Date.now() - this._lastSessionTime;
-        let timeout = Services.prefs.getIntPref("browser.sessionstore.resume_from_crash_timeout");
-        if (delta > (timeout * 60000))
-          this._shouldRestore = false;
+        this._sessionFile.copyTo(null, this._sessionFileBackup.leafName);
 
-        this._sessionFile.copyTo(null, this._sessionFileBackup.leafName);
+        switch(Services.metro.previousExecutionState) {
+          // 0 == NotRunning
+          case 0:
+            // Disable crash recovery if we have exceeded the timeout
+            this._lastSessionTime = this._sessionFile.lastModifiedTime;
+            let delta = Date.now() - this._lastSessionTime;
+            let timeout =
+              Services.prefs.getIntPref(
+                  "browser.sessionstore.resume_from_crash_timeout");
+            this._shouldRestore = shutdownWasUnclean
+                                && (delta < (timeout * 60000));
+            break;
+          // 1 == Running
+          case 1:
+            // We should never encounter this situation
+            Components.utils.reportError("SessionRestore.init called with "
+                                       + "previous execution state 'Running'");
+            this._shouldRestore = true;
+            break;
+          // 2 == Suspended
+          case 2:
+            // We should never encounter this situation
+            Components.utils.reportError("SessionRestore.init called with "
+                                       + "previous execution state 'Suspended'");
+            this._shouldRestore = true;
+            break;
+          // 3 == Terminated
+          case 3:
+            // Terminated means that Windows terminated our already-suspended
+            // process to get back some resources. When we re-launch, we want
+            // to provide the illusion that our process was suspended the
+            // whole time, and never terminated.
+            this._shouldRestore = true;
+            break;
+          // 4 == ClosedByUser
+          case 4:
+            // ClosedByUser indicates that the user performed a "close" gesture
+            // on our tile. We should act as if the browser closed normally,
+            // even if we were closed from a suspended state (in which case
+            // we'll have determined that it was an unclean shtudown)
+            this._shouldRestore = false;
+            break;
+        }
       }
 
-      if (!this._sessionCache.exists() || !this._sessionCache.isDirectory())
+      if (!this._sessionCache.exists() || !this._sessionCache.isDirectory()) {
         this._sessionCache.create(Ci.nsIFile.DIRECTORY_TYPE, 0700);
+      }
     } catch (ex) {
       Cu.reportError(ex); // file was write-locked?
     }
 
     this._interval = Services.prefs.getIntPref("browser.sessionstore.interval");
     this._maxTabsUndo = Services.prefs.getIntPref("browser.sessionstore.max_tabs_undo");
 
     // Disable crash recovery if it has been turned off
--- a/widget/nsIWinMetroUtils.idl
+++ b/widget/nsIWinMetroUtils.idl
@@ -7,30 +7,37 @@
 
 /**
  * Integration with the "Metro"/"Modern" UI environment in Windows 8.
  *
  * Note: browser/metro/base/content/browser-scripts.js contains a stub
  * implementation of this interface for non-Windows systems, for testing and
  * development purposes only.
  */
-[scriptable, uuid(d30daa27-ce2b-4503-80cc-b162f4c24e93)]
+[scriptable, uuid(148f57d3-51df-4e5c-a40b-7ae5ee76188e)]
 interface nsIWinMetroUtils : nsISupports
 {
   /**
    * Determine if the current browser is running in the metro immersive
    * environment.
    */
   readonly attribute boolean immersive;
 
   /**
    * Determine the activation URI
    */
   readonly attribute AString activationURI;
 
+  /**
+   * Determine the previous execution state. The possible values of this
+   * attribute are exactly those values in the
+   * Windows::ApplicationModel::Activation enumeration.
+   */
+  readonly attribute long previousExecutionState;
+
    /**
     * Show the settings flyout
     */
    void showSettingsFlyout();
 
   /**
    * Launches the specified application with the specified arguments and
    * switches to Desktop mode if in metro mode.
--- a/widget/windows/winrt/FrameworkView.cpp
+++ b/widget/windows/winrt/FrameworkView.cpp
@@ -347,25 +347,30 @@ FrameworkView::OnWindowVisibilityChanged
 }
 
 HRESULT
 FrameworkView::OnActivated(ICoreApplicationView* aApplicationView,
                            IActivatedEventArgs* aArgs)
 {
   LogFunction();
 
-  ApplicationExecutionState state;
-  aArgs->get_PreviousExecutionState(&state);
-  bool startup = state == ApplicationExecutionState::ApplicationExecutionState_Terminated ||
-                 state == ApplicationExecutionState::ApplicationExecutionState_ClosedByUser ||
-                 state == ApplicationExecutionState::ApplicationExecutionState_NotRunning;
+  aArgs->get_PreviousExecutionState(&mPreviousExecutionState);
+  bool startup = mPreviousExecutionState == ApplicationExecutionState::ApplicationExecutionState_Terminated ||
+                 mPreviousExecutionState == ApplicationExecutionState::ApplicationExecutionState_ClosedByUser ||
+                 mPreviousExecutionState == ApplicationExecutionState::ApplicationExecutionState_NotRunning;
   ProcessActivationArgs(aArgs, startup);
   return S_OK;
 }
 
+int
+FrameworkView::GetPreviousExecutionState()
+{
+  return mPreviousExecutionState;
+}
+
 HRESULT
 FrameworkView::OnSoftkeyboardHidden(IInputPane* aSender,
                                     IInputPaneVisibilityEventArgs* aArgs)
 {
   LogFunction();
   if (mShuttingDown)
     return S_OK;
   sKeyboardIsVisible = false;
--- a/widget/windows/winrt/FrameworkView.h
+++ b/widget/windows/winrt/FrameworkView.h
@@ -76,16 +76,17 @@ public:
   STDMETHODIMP SetWindow(ICoreWindow* aWindow);
   STDMETHODIMP Load(HSTRING aEntryPoint);
   STDMETHODIMP Run();
   STDMETHODIMP Uninitialize();
 
   HRESULT ActivateView();
 
   // Public apis for MetroWidget
+  int GetPreviousExecutionState();
   void ShutdownXPCOM();
   float GetDPI() { return mDPI; }
   ICoreWindow* GetCoreWindow() { return mWindow.Get(); }
   void SetWidget(MetroWidget* aWidget);
   MetroWidget* GetWidget() { return mWidget.Get(); }
   void GetBounds(nsIntRect &aRect);
   void GetActivationURI(nsAString &aActivationURI) { aActivationURI = mActivationURI; }
   void SetCursor(ABI::Windows::UI::Core::CoreCursorType aCursorType, DWORD aCustomId = 0);
@@ -172,16 +173,17 @@ private:
   EventRegistrationToken mAutomationProviderRequested;
   EventRegistrationToken mDataTransferRequested;
   EventRegistrationToken mSearchQuerySubmitted;
   EventRegistrationToken mPlayToRequested;
   EventRegistrationToken mSettingsPane;
   EventRegistrationToken mPrintManager;
 
 private:
+  ABI::Windows::ApplicationModel::Activation::ApplicationExecutionState mPreviousExecutionState;
   nsIntRect mWindowBounds; // in device-pixel coordinates
   float mDPI;
   bool mShuttingDown;
   nsAutoString mActivationURI;
   nsAutoString mActivationCommandLine;
   Microsoft::WRL::ComPtr<IInspectable> mAutomationProvider;
   //Microsoft::WRL::ComPtr<ID2D1PrintControl> mD2DPrintControl;
   // Private critical section protects D2D device context for on-screen
--- a/widget/windows/winrt/nsWinMetroUtils.cpp
+++ b/widget/windows/winrt/nsWinMetroUtils.cpp
@@ -243,16 +243,27 @@ nsWinMetroUtils::GetActivationURI(nsAStr
     NS_WARNING("GetActivationURI used before view is created!");
     return NS_OK;
   }
   sFrameworkView->GetActivationURI(aActivationURI);
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsWinMetroUtils::GetPreviousExecutionState(int32_t *out)
+{
+  if (!sFrameworkView) {
+    NS_WARNING("GetPreviousExecutionState used before view is created!");
+    return NS_OK;
+  }
+  *out = sFrameworkView->GetPreviousExecutionState();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsWinMetroUtils::GetKeyboardVisible(bool *aImersive)
 {
   *aImersive = mozilla::widget::winrt::FrameworkView::IsKeyboardVisible();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsWinMetroUtils::GetKeyboardX(uint32_t *aX)