Bug 846365 - Add proper handling for background session closes in Firefox for Metro. r=jimm
authorBrian R. Bondy <netzen@gmail.com>
Sun, 24 Mar 2013 19:10:46 -0400
changeset 126081 ea59a801aabfccbcd33d80c645c3d8c8e0bb218f
parent 126080 abef045c80bca341ed88c2a9f7b4baf85355a77f
child 126082 683bb0caab3ad5e5bf639fa64a9b64d6ba00646f
push id24473
push userjdrew@mozilla.com
push dateMon, 25 Mar 2013 16:34:49 +0000
treeherdermozilla-central@4d3250f3afea [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjimm
bugs846365
milestone22.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 846365 - Add proper handling for background session closes in Firefox for Metro. r=jimm
browser/app/nsBrowserApp.cpp
toolkit/xre/nsAppRunner.cpp
widget/windows/winrt/MetroApp.cpp
--- a/browser/app/nsBrowserApp.cpp
+++ b/browser/app/nsBrowserApp.cpp
@@ -186,16 +186,20 @@ static int do_main(int argc, char* argv[
     // This command-line flag is passed to our executable when it is to be
     // launched in metro mode (i.e. our EXE is registered as the default
     // browser and the user has tapped our EXE's tile)
     if (IsArg(argv[1], "ServerName:DefaultBrowserServer")) {
       mainFlags = XRE_MAIN_FLAG_USE_METRO;
       argv[1] = argv[0];
       argv++;
       argc--;
+    } else if (IsArg(argv[1], "BackgroundSessionClosed")) {
+      // This command line flag is used for indirect shutdowns, the OS
+      // relaunches Metro Firefox with this command line arg.
+      mainFlags = XRE_MAIN_FLAG_USE_METRO;
     } else {
       // This command-line flag is used to test the metro browser in a desktop
       // environment.
       for (int idx = 1; idx < argc; idx++) {
         if (IsArg(argv[idx], "metrodesktop")) {
           metroOnDesktop = true;
           break;
         } 
--- a/toolkit/xre/nsAppRunner.cpp
+++ b/toolkit/xre/nsAppRunner.cpp
@@ -4023,34 +4023,36 @@ XREMain::XRE_main(int argc, char* argv[]
 }
 
 #if defined(MOZ_METRO) && defined(XP_WIN)
 extern bool XRE_MetroCoreApplicationRun();
 static XREMain* xreMainPtr;
 
 // must be called by the thread we want as the main thread
 nsresult
-XRE_metroStartup()
+XRE_metroStartup(bool runXREMain)
 {
   nsresult rv;
 
   bool exit = false;
   if (xreMainPtr->XRE_mainStartup(&exit) != 0 || exit)
     return NS_ERROR_FAILURE;
 
   // Start the real application
   xreMainPtr->mScopedXPCom = new ScopedXPCOMStartup();
   if (!xreMainPtr->mScopedXPCom)
     return NS_ERROR_FAILURE;
 
   rv = xreMainPtr->mScopedXPCom->Initialize();
   NS_ENSURE_SUCCESS(rv, rv);
 
-  rv = xreMainPtr->XRE_mainRun();
-  NS_ENSURE_SUCCESS(rv, rv);
+  if (runXREMain) {
+    rv = xreMainPtr->XRE_mainRun();
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
   return NS_OK;
 }
 
 void
 XRE_metroShutdown()
 {
   delete xreMainPtr->mScopedXPCom;
   xreMainPtr->mScopedXPCom = nullptr;
--- a/widget/windows/winrt/MetroApp.cpp
+++ b/widget/windows/winrt/MetroApp.cpp
@@ -6,28 +6,30 @@
 #include "MetroApp.h"
 #include "MetroWidget.h"
 #include "mozilla/widget/AudioSession.h"
 #include "nsIRunnable.h"
 #include "MetroUtils.h"
 #include "MetroAppShell.h"
 #include "nsICommandLineRunner.h"
 #include "FrameworkView.h"
+#include "nsAppDirectoryServiceDefs.h"
+#include <shellapi.h>
 
 using namespace ABI::Windows::ApplicationModel;
 using namespace ABI::Windows::ApplicationModel::Core;
 using namespace ABI::Windows::UI::Core;
 using namespace ABI::Windows::System;
 using namespace ABI::Windows::Foundation;
 using namespace Microsoft::WRL;
 using namespace Microsoft::WRL::Wrappers;
 
 // Metro specific XRE methods we call from here on an
 // appropriate thread.
-extern nsresult XRE_metroStartup();
+extern nsresult XRE_metroStartup(bool runXREMain);
 extern void XRE_metroShutdown();
 
 #ifdef PR_LOGGING
 extern PRLogModuleInfo* gWindowsLog;
 #endif
 
 namespace mozilla {
 namespace widget {
@@ -63,17 +65,17 @@ MetroApp::Initialize()
 {
   HRESULT hr;
   LogThread();
 
   static bool xpcomInit;
   if (!xpcomInit) {
     xpcomInit = true;
     Log(L"XPCOM startup initialization began");
-    nsresult rv = XRE_metroStartup();
+    nsresult rv = XRE_metroStartup(true);
     Log(L"XPCOM startup initialization complete");
     if (NS_FAILED(rv)) {
       Log(L"XPCOM startup initialization failed, bailing. rv=%X", rv);
       CoreExit();
       return;
     }
   }
 
@@ -190,16 +192,27 @@ MetroApp::PostSleepWakeNotification(cons
   }
   isSleep = aIsSleep;
   MetroUtils::FireObserver(aIsSleep ? "sleep_notification" :
                                       "wake_notification");
 }
 
 } } }
 
+
+static bool
+IsBackgroundSessionClosedStartup()
+{
+  int argc;
+  LPWSTR *argv = CommandLineToArgvW(GetCommandLineW(), &argc);
+  bool backgroundSessionClosed = argc > 1 && !wcsicmp(argv[1], L"-BackgroundSessionClosed");
+  LocalFree(argv);
+  return backgroundSessionClosed;
+}
+
 bool
 XRE_MetroCoreApplicationRun()
 {
   HRESULT hr;
   LogThread();
 
   using namespace mozilla::widget::winrt;
 
@@ -214,17 +227,38 @@ XRE_MetroCoreApplicationRun()
   HStringReference className(RuntimeClass_Windows_ApplicationModel_Core_CoreApplication);
   hr = GetActivationFactory(className.Get(), sCoreApp.GetAddressOf());
   if (FAILED(hr)) {
     LogHRESULT(hr);
     return false;
   }
 
   sFrameworkView = Make<FrameworkView>(sMetroApp.Get());
-  sCoreApp->Run(sMetroApp.Get());
+
+  // Perform any cleanup for unclean shutdowns here, such as when the background session
+  // is closed via the appbar on the left when outside of Metro.  Windows restarts the
+  // process solely for cleanup reasons.
+  if (IsBackgroundSessionClosedStartup() && SUCCEEDED(XRE_metroStartup(false))) {
+
+    // Whether or  not to use sessionstore depends on if the bak exists.  Since host process
+    // shutdown isn't a crash we shouldn't restore sessionstore.
+    nsCOMPtr<nsIFile> sessionBAK;
+    if (NS_FAILED(NS_GetSpecialDirectory("ProfDS", getter_AddRefs(sessionBAK)))) {
+      return false;
+    }
+
+    sessionBAK->AppendNative(nsDependentCString("sessionstore.bak"));
+    bool exists;
+    if (NS_SUCCEEDED(sessionBAK->Exists(&exists)) && exists) {
+      sessionBAK->Remove(false);
+    }
+    return false;
+  }
+
+  hr = sCoreApp->Run(sMetroApp.Get());
 
   Log(L"Exiting CoreApplication::Run");
 
   sFrameworkView = nullptr;
   sCoreApp = nullptr;
   sMetroApp = nullptr;
 
   return true;