toolkit/components/startup/nsAppStartup.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/toolkit/components/startup/nsAppStartup.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,968 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#include "nsAppStartup.h"
    1.10 +
    1.11 +#include "nsIAppShellService.h"
    1.12 +#include "nsPIDOMWindow.h"
    1.13 +#include "nsIInterfaceRequestor.h"
    1.14 +#include "nsIFile.h"
    1.15 +#include "nsIObserverService.h"
    1.16 +#include "nsIPrefBranch.h"
    1.17 +#include "nsIPrefService.h"
    1.18 +#include "nsIPromptService.h"
    1.19 +#include "nsIStringBundle.h"
    1.20 +#include "nsISupportsPrimitives.h"
    1.21 +#include "nsIWebBrowserChrome.h"
    1.22 +#include "nsIWindowMediator.h"
    1.23 +#include "nsIWindowWatcher.h"
    1.24 +#include "nsIXULRuntime.h"
    1.25 +#include "nsIXULWindow.h"
    1.26 +#include "nsNativeCharsetUtils.h"
    1.27 +#include "nsThreadUtils.h"
    1.28 +#include "nsAutoPtr.h"
    1.29 +#include "nsString.h"
    1.30 +#include "mozilla/Preferences.h"
    1.31 +#include "GeckoProfiler.h"
    1.32 +
    1.33 +#include "prprf.h"
    1.34 +#include "nsIInterfaceRequestorUtils.h"
    1.35 +#include "nsWidgetsCID.h"
    1.36 +#include "nsAppShellCID.h"
    1.37 +#include "nsXPCOMCIDInternal.h"
    1.38 +#include "mozilla/Services.h"
    1.39 +#include "nsIXPConnect.h"
    1.40 +#include "jsapi.h"
    1.41 +#include "prenv.h"
    1.42 +#include "nsAppDirectoryServiceDefs.h"
    1.43 +
    1.44 +#if defined(XP_WIN)
    1.45 +// Prevent collisions with nsAppStartup::GetStartupInfo()
    1.46 +#undef GetStartupInfo
    1.47 +#endif
    1.48 +
    1.49 +#include "mozilla/IOInterposer.h"
    1.50 +#include "mozilla/Telemetry.h"
    1.51 +#include "mozilla/StartupTimeline.h"
    1.52 +
    1.53 +static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
    1.54 +
    1.55 +#define kPrefLastSuccess "toolkit.startup.last_success"
    1.56 +#define kPrefMaxResumedCrashes "toolkit.startup.max_resumed_crashes"
    1.57 +#define kPrefRecentCrashes "toolkit.startup.recent_crashes"
    1.58 +#define kPrefAlwaysUseSafeMode "toolkit.startup.always_use_safe_mode"
    1.59 +
    1.60 +#if defined(XP_WIN)
    1.61 +#include "mozilla/perfprobe.h"
    1.62 +/**
    1.63 + * Events sent to the system for profiling purposes
    1.64 + */
    1.65 +//Keep them syncronized with the .mof file
    1.66 +
    1.67 +//Process-wide GUID, used by the OS to differentiate sources
    1.68 +// {509962E0-406B-46F4-99BA-5A009F8D2225}
    1.69 +//Keep it synchronized with the .mof file
    1.70 +#define NS_APPLICATION_TRACING_CID \
    1.71 +  { 0x509962E0, 0x406B, 0x46F4, \
    1.72 +  { 0x99, 0xBA, 0x5A, 0x00, 0x9F, 0x8D, 0x22, 0x25} }
    1.73 +
    1.74 +//Event-specific GUIDs, used by the OS to differentiate events
    1.75 +// {A3DA04E0-57D7-482A-A1C1-61DA5F95BACB}
    1.76 +#define NS_PLACES_INIT_COMPLETE_EVENT_CID \
    1.77 +  { 0xA3DA04E0, 0x57D7, 0x482A, \
    1.78 +  { 0xA1, 0xC1, 0x61, 0xDA, 0x5F, 0x95, 0xBA, 0xCB} }
    1.79 +// {917B96B1-ECAD-4DAB-A760-8D49027748AE}
    1.80 +#define NS_SESSION_STORE_WINDOW_RESTORED_EVENT_CID \
    1.81 +  { 0x917B96B1, 0xECAD, 0x4DAB, \
    1.82 +  { 0xA7, 0x60, 0x8D, 0x49, 0x02, 0x77, 0x48, 0xAE} }
    1.83 +// {26D1E091-0AE7-4F49-A554-4214445C505C}
    1.84 +#define NS_XPCOM_SHUTDOWN_EVENT_CID \
    1.85 +  { 0x26D1E091, 0x0AE7, 0x4F49, \
    1.86 +  { 0xA5, 0x54, 0x42, 0x14, 0x44, 0x5C, 0x50, 0x5C} }
    1.87 +
    1.88 +static NS_DEFINE_CID(kApplicationTracingCID,
    1.89 +  NS_APPLICATION_TRACING_CID);
    1.90 +static NS_DEFINE_CID(kPlacesInitCompleteCID,
    1.91 +  NS_PLACES_INIT_COMPLETE_EVENT_CID);
    1.92 +static NS_DEFINE_CID(kSessionStoreWindowRestoredCID,
    1.93 +  NS_SESSION_STORE_WINDOW_RESTORED_EVENT_CID);
    1.94 +static NS_DEFINE_CID(kXPCOMShutdownCID,
    1.95 +  NS_XPCOM_SHUTDOWN_EVENT_CID);  
    1.96 +#endif //defined(XP_WIN)
    1.97 +
    1.98 +using namespace mozilla;
    1.99 +
   1.100 +uint32_t gRestartMode = 0;
   1.101 +
   1.102 +class nsAppExitEvent : public nsRunnable {
   1.103 +private:
   1.104 +  nsRefPtr<nsAppStartup> mService;
   1.105 +
   1.106 +public:
   1.107 +  nsAppExitEvent(nsAppStartup *service) : mService(service) {}
   1.108 +
   1.109 +  NS_IMETHOD Run() {
   1.110 +    // Tell the appshell to exit
   1.111 +    mService->mAppShell->Exit();
   1.112 +
   1.113 +    mService->mRunning = false;
   1.114 +    return NS_OK;
   1.115 +  }
   1.116 +};
   1.117 +
   1.118 +/**
   1.119 + * Computes an approximation of the absolute time represented by @a stamp
   1.120 + * which is comparable to those obtained via PR_Now(). If the current absolute
   1.121 + * time varies a lot (e.g. DST adjustments) since the first call then the
   1.122 + * resulting times may be inconsistent.
   1.123 + *
   1.124 + * @param stamp The timestamp to be converted
   1.125 + * @returns The converted timestamp
   1.126 + */
   1.127 +uint64_t ComputeAbsoluteTimestamp(PRTime prnow, TimeStamp now, TimeStamp stamp)
   1.128 +{
   1.129 +  static PRTime sAbsoluteNow = PR_Now();
   1.130 +  static TimeStamp sMonotonicNow = TimeStamp::Now();
   1.131 +
   1.132 +  return sAbsoluteNow - (sMonotonicNow - stamp).ToMicroseconds();
   1.133 +}
   1.134 +
   1.135 +//
   1.136 +// nsAppStartup
   1.137 +//
   1.138 +
   1.139 +nsAppStartup::nsAppStartup() :
   1.140 +  mConsiderQuitStopper(0),
   1.141 +  mRunning(false),
   1.142 +  mShuttingDown(false),
   1.143 +  mStartingUp(true),
   1.144 +  mAttemptingQuit(false),
   1.145 +  mRestart(false),
   1.146 +  mInterrupted(false),
   1.147 +  mIsSafeModeNecessary(false),
   1.148 +  mStartupCrashTrackingEnded(false),
   1.149 +  mRestartTouchEnvironment(false)
   1.150 +{ }
   1.151 +
   1.152 +
   1.153 +nsresult
   1.154 +nsAppStartup::Init()
   1.155 +{
   1.156 +  nsresult rv;
   1.157 +
   1.158 +  // Create widget application shell
   1.159 +  mAppShell = do_GetService(kAppShellCID, &rv);
   1.160 +  NS_ENSURE_SUCCESS(rv, rv);
   1.161 +
   1.162 +  nsCOMPtr<nsIObserverService> os =
   1.163 +    mozilla::services::GetObserverService();
   1.164 +  if (!os)
   1.165 +    return NS_ERROR_FAILURE;
   1.166 +
   1.167 +  os->AddObserver(this, "quit-application-forced", true);
   1.168 +  os->AddObserver(this, "sessionstore-init-started", true);
   1.169 +  os->AddObserver(this, "sessionstore-windows-restored", true);
   1.170 +  os->AddObserver(this, "profile-change-teardown", true);
   1.171 +  os->AddObserver(this, "xul-window-registered", true);
   1.172 +  os->AddObserver(this, "xul-window-destroyed", true);
   1.173 +  os->AddObserver(this, "xpcom-shutdown", true);
   1.174 +
   1.175 +#if defined(XP_WIN)
   1.176 +  os->AddObserver(this, "places-init-complete", true);
   1.177 +  // This last event is only interesting to us for xperf-based measures
   1.178 +
   1.179 +  // Initialize interaction with profiler
   1.180 +  mProbesManager =
   1.181 +    new ProbeManager(
   1.182 +                     kApplicationTracingCID,
   1.183 +                     NS_LITERAL_CSTRING("Application startup probe"));
   1.184 +  // Note: The operation is meant mostly for in-house profiling.
   1.185 +  // Therefore, we do not warn if probes manager cannot be initialized
   1.186 +
   1.187 +  if (mProbesManager) {
   1.188 +    mPlacesInitCompleteProbe =
   1.189 +      mProbesManager->
   1.190 +      GetProbe(kPlacesInitCompleteCID,
   1.191 +               NS_LITERAL_CSTRING("places-init-complete"));
   1.192 +    NS_WARN_IF_FALSE(mPlacesInitCompleteProbe,
   1.193 +                     "Cannot initialize probe 'places-init-complete'");
   1.194 +
   1.195 +    mSessionWindowRestoredProbe =
   1.196 +      mProbesManager->
   1.197 +      GetProbe(kSessionStoreWindowRestoredCID,
   1.198 +               NS_LITERAL_CSTRING("sessionstore-windows-restored"));
   1.199 +    NS_WARN_IF_FALSE(mSessionWindowRestoredProbe,
   1.200 +                     "Cannot initialize probe 'sessionstore-windows-restored'");
   1.201 +                     
   1.202 +    mXPCOMShutdownProbe =
   1.203 +      mProbesManager->
   1.204 +      GetProbe(kXPCOMShutdownCID,
   1.205 +               NS_LITERAL_CSTRING("xpcom-shutdown"));
   1.206 +    NS_WARN_IF_FALSE(mXPCOMShutdownProbe,
   1.207 +                     "Cannot initialize probe 'xpcom-shutdown'");
   1.208 +
   1.209 +    rv = mProbesManager->StartSession();
   1.210 +    NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
   1.211 +                     "Cannot initialize system probe manager");
   1.212 +  }
   1.213 +#endif //defined(XP_WIN)
   1.214 +
   1.215 +  return NS_OK;
   1.216 +}
   1.217 +
   1.218 +
   1.219 +//
   1.220 +// nsAppStartup->nsISupports
   1.221 +//
   1.222 +
   1.223 +NS_IMPL_ISUPPORTS(nsAppStartup,
   1.224 +                  nsIAppStartup,
   1.225 +                  nsIWindowCreator,
   1.226 +                  nsIWindowCreator2,
   1.227 +                  nsIObserver,
   1.228 +                  nsISupportsWeakReference)
   1.229 +
   1.230 +
   1.231 +//
   1.232 +// nsAppStartup->nsIAppStartup
   1.233 +//
   1.234 +
   1.235 +NS_IMETHODIMP
   1.236 +nsAppStartup::CreateHiddenWindow()
   1.237 +{
   1.238 +#ifdef MOZ_WIDGET_GONK
   1.239 +  return NS_OK;
   1.240 +#else
   1.241 +  nsCOMPtr<nsIAppShellService> appShellService
   1.242 +    (do_GetService(NS_APPSHELLSERVICE_CONTRACTID));
   1.243 +  NS_ENSURE_TRUE(appShellService, NS_ERROR_FAILURE);
   1.244 +
   1.245 +  return appShellService->CreateHiddenWindow();
   1.246 +#endif
   1.247 +}
   1.248 +
   1.249 +
   1.250 +NS_IMETHODIMP
   1.251 +nsAppStartup::DestroyHiddenWindow()
   1.252 +{
   1.253 +#ifdef MOZ_WIDGET_GONK
   1.254 +  return NS_OK;
   1.255 +#else
   1.256 +  nsCOMPtr<nsIAppShellService> appShellService
   1.257 +    (do_GetService(NS_APPSHELLSERVICE_CONTRACTID));
   1.258 +  NS_ENSURE_TRUE(appShellService, NS_ERROR_FAILURE);
   1.259 +
   1.260 +  return appShellService->DestroyHiddenWindow();
   1.261 +#endif
   1.262 +}
   1.263 +
   1.264 +NS_IMETHODIMP
   1.265 +nsAppStartup::Run(void)
   1.266 +{
   1.267 +  NS_ASSERTION(!mRunning, "Reentrant appstartup->Run()");
   1.268 +
   1.269 +  // If we have no windows open and no explicit calls to
   1.270 +  // enterLastWindowClosingSurvivalArea, or somebody has explicitly called
   1.271 +  // quit, don't bother running the event loop which would probably leave us
   1.272 +  // with a zombie process.
   1.273 +
   1.274 +  if (!mShuttingDown && mConsiderQuitStopper != 0) {
   1.275 +#ifdef XP_MACOSX
   1.276 +    EnterLastWindowClosingSurvivalArea();
   1.277 +#endif
   1.278 +
   1.279 +    mRunning = true;
   1.280 +
   1.281 +    nsresult rv = mAppShell->Run();
   1.282 +    if (NS_FAILED(rv))
   1.283 +      return rv;
   1.284 +  }
   1.285 +
   1.286 +  nsresult retval = NS_OK;
   1.287 +  if (mRestartTouchEnvironment) {
   1.288 +    retval = NS_SUCCESS_RESTART_METRO_APP;
   1.289 +  } else if (mRestart) {
   1.290 +    retval = NS_SUCCESS_RESTART_APP;
   1.291 +  }
   1.292 +
   1.293 +  return retval;
   1.294 +}
   1.295 +
   1.296 +
   1.297 +
   1.298 +NS_IMETHODIMP
   1.299 +nsAppStartup::Quit(uint32_t aMode)
   1.300 +{
   1.301 +  uint32_t ferocity = (aMode & 0xF);
   1.302 +
   1.303 +  // Quit the application. We will asynchronously call the appshell's
   1.304 +  // Exit() method via nsAppExitEvent to allow one last pass
   1.305 +  // through any events in the queue. This guarantees a tidy cleanup.
   1.306 +  nsresult rv = NS_OK;
   1.307 +  bool postedExitEvent = false;
   1.308 +
   1.309 +  if (mShuttingDown)
   1.310 +    return NS_OK;
   1.311 +
   1.312 +  // If we're considering quitting, we will only do so if:
   1.313 +  if (ferocity == eConsiderQuit) {
   1.314 +#ifdef XP_MACOSX
   1.315 +    nsCOMPtr<nsIAppShellService> appShell
   1.316 +      (do_GetService(NS_APPSHELLSERVICE_CONTRACTID));
   1.317 +    bool hasHiddenPrivateWindow = false;
   1.318 +    if (appShell) {
   1.319 +      appShell->GetHasHiddenPrivateWindow(&hasHiddenPrivateWindow);
   1.320 +    }
   1.321 +    int32_t suspiciousCount = hasHiddenPrivateWindow ? 2 : 1;
   1.322 +#endif
   1.323 +
   1.324 +    if (mConsiderQuitStopper == 0) {
   1.325 +      // there are no windows...
   1.326 +      ferocity = eAttemptQuit;
   1.327 +    }
   1.328 +#ifdef XP_MACOSX
   1.329 +    else if (mConsiderQuitStopper == suspiciousCount) {
   1.330 +      // ... or there is only a hiddenWindow left, and it's useless:
   1.331 +
   1.332 +      // Failure shouldn't be fatal, but will abort quit attempt:
   1.333 +      if (!appShell)
   1.334 +        return NS_OK;
   1.335 +
   1.336 +      bool usefulHiddenWindow;
   1.337 +      appShell->GetApplicationProvidedHiddenWindow(&usefulHiddenWindow);
   1.338 +      nsCOMPtr<nsIXULWindow> hiddenWindow;
   1.339 +      appShell->GetHiddenWindow(getter_AddRefs(hiddenWindow));
   1.340 +      // If the remaining windows are useful, we won't quit:
   1.341 +      nsCOMPtr<nsIXULWindow> hiddenPrivateWindow;
   1.342 +      if (hasHiddenPrivateWindow) {
   1.343 +        appShell->GetHiddenPrivateWindow(getter_AddRefs(hiddenPrivateWindow));
   1.344 +        if ((!hiddenWindow && !hiddenPrivateWindow) || usefulHiddenWindow)
   1.345 +          return NS_OK;
   1.346 +      } else if (!hiddenWindow || usefulHiddenWindow) {
   1.347 +        return NS_OK;
   1.348 +      }
   1.349 +
   1.350 +      ferocity = eAttemptQuit;
   1.351 +    }
   1.352 +#endif
   1.353 +  }
   1.354 +
   1.355 +  nsCOMPtr<nsIObserverService> obsService;
   1.356 +  if (ferocity == eAttemptQuit || ferocity == eForceQuit) {
   1.357 +
   1.358 +    nsCOMPtr<nsISimpleEnumerator> windowEnumerator;
   1.359 +    nsCOMPtr<nsIWindowMediator> mediator (do_GetService(NS_WINDOWMEDIATOR_CONTRACTID));
   1.360 +    if (mediator) {
   1.361 +      mediator->GetEnumerator(nullptr, getter_AddRefs(windowEnumerator));
   1.362 +      if (windowEnumerator) {
   1.363 +        bool more;
   1.364 +        while (windowEnumerator->HasMoreElements(&more), more) {
   1.365 +          nsCOMPtr<nsISupports> window;
   1.366 +          windowEnumerator->GetNext(getter_AddRefs(window));
   1.367 +          nsCOMPtr<nsPIDOMWindow> domWindow(do_QueryInterface(window));
   1.368 +          if (domWindow) {
   1.369 +            if (!domWindow->CanClose())
   1.370 +              return NS_OK;
   1.371 +          }
   1.372 +        }
   1.373 +      }
   1.374 +    }
   1.375 +
   1.376 +    PROFILER_MARKER("Shutdown start");
   1.377 +    mozilla::RecordShutdownStartTimeStamp();
   1.378 +    mShuttingDown = true;
   1.379 +    if (!mRestart) {
   1.380 +      mRestart = (aMode & eRestart) != 0;
   1.381 +      gRestartMode = (aMode & 0xF0);
   1.382 +    }
   1.383 +
   1.384 +    if (!mRestartTouchEnvironment) {
   1.385 +      mRestartTouchEnvironment = (aMode & eRestartTouchEnvironment) != 0;
   1.386 +      gRestartMode = (aMode & 0xF0);
   1.387 +    }
   1.388 +
   1.389 +    if (mRestart || mRestartTouchEnvironment) {
   1.390 +      // Mark the next startup as a restart.
   1.391 +      PR_SetEnv("MOZ_APP_RESTART=1");
   1.392 +
   1.393 +      /* Firefox-restarts reuse the process so regular process start-time isn't
   1.394 +         a useful indicator of startup time anymore. */
   1.395 +      TimeStamp::RecordProcessRestart();
   1.396 +    }
   1.397 +
   1.398 +    obsService = mozilla::services::GetObserverService();
   1.399 +
   1.400 +    if (!mAttemptingQuit) {
   1.401 +      mAttemptingQuit = true;
   1.402 +#ifdef XP_MACOSX
   1.403 +      // now even the Mac wants to quit when the last window is closed
   1.404 +      ExitLastWindowClosingSurvivalArea();
   1.405 +#endif
   1.406 +      if (obsService)
   1.407 +        obsService->NotifyObservers(nullptr, "quit-application-granted", nullptr);
   1.408 +    }
   1.409 +
   1.410 +    /* Enumerate through each open window and close it. It's important to do
   1.411 +       this before we forcequit because this can control whether we really quit
   1.412 +       at all. e.g. if one of these windows has an unload handler that
   1.413 +       opens a new window. Ugh. I know. */
   1.414 +    CloseAllWindows();
   1.415 +
   1.416 +    if (mediator) {
   1.417 +      if (ferocity == eAttemptQuit) {
   1.418 +        ferocity = eForceQuit; // assume success
   1.419 +
   1.420 +        /* Were we able to immediately close all windows? if not, eAttemptQuit
   1.421 +           failed. This could happen for a variety of reasons; in fact it's
   1.422 +           very likely. Perhaps we're being called from JS and the window->Close
   1.423 +           method hasn't had a chance to wrap itself up yet. So give up.
   1.424 +           We'll return (with eConsiderQuit) as the remaining windows are
   1.425 +           closed. */
   1.426 +        mediator->GetEnumerator(nullptr, getter_AddRefs(windowEnumerator));
   1.427 +        if (windowEnumerator) {
   1.428 +          bool more;
   1.429 +          while (windowEnumerator->HasMoreElements(&more), more) {
   1.430 +            /* we can't quit immediately. we'll try again as the last window
   1.431 +               finally closes. */
   1.432 +            ferocity = eAttemptQuit;
   1.433 +            nsCOMPtr<nsISupports> window;
   1.434 +            windowEnumerator->GetNext(getter_AddRefs(window));
   1.435 +            nsCOMPtr<nsIDOMWindow> domWindow = do_QueryInterface(window);
   1.436 +            if (domWindow) {
   1.437 +              bool closed = false;
   1.438 +              domWindow->GetClosed(&closed);
   1.439 +              if (!closed) {
   1.440 +                rv = NS_ERROR_FAILURE;
   1.441 +                break;
   1.442 +              }
   1.443 +            }
   1.444 +          }
   1.445 +        }
   1.446 +      }
   1.447 +    }
   1.448 +  }
   1.449 +
   1.450 +  if (ferocity == eForceQuit) {
   1.451 +    // do it!
   1.452 +
   1.453 +    // No chance of the shutdown being cancelled from here on; tell people
   1.454 +    // we're shutting down for sure while all services are still available.
   1.455 +    if (obsService) {
   1.456 +      NS_NAMED_LITERAL_STRING(shutdownStr, "shutdown");
   1.457 +      NS_NAMED_LITERAL_STRING(restartStr, "restart");
   1.458 +      obsService->NotifyObservers(nullptr, "quit-application",
   1.459 +        (mRestart || mRestartTouchEnvironment) ?
   1.460 +         restartStr.get() : shutdownStr.get());
   1.461 +    }
   1.462 +
   1.463 +    if (!mRunning) {
   1.464 +      postedExitEvent = true;
   1.465 +    }
   1.466 +    else {
   1.467 +      // no matter what, make sure we send the exit event.  If
   1.468 +      // worst comes to worst, we'll do a leaky shutdown but we WILL
   1.469 +      // shut down. Well, assuming that all *this* stuff works ;-).
   1.470 +      nsCOMPtr<nsIRunnable> event = new nsAppExitEvent(this);
   1.471 +      rv = NS_DispatchToCurrentThread(event);
   1.472 +      if (NS_SUCCEEDED(rv)) {
   1.473 +        postedExitEvent = true;
   1.474 +      }
   1.475 +      else {
   1.476 +        NS_WARNING("failed to dispatch nsAppExitEvent");
   1.477 +      }
   1.478 +    }
   1.479 +  }
   1.480 +
   1.481 +  // turn off the reentrancy check flag, but not if we have
   1.482 +  // more asynchronous work to do still.
   1.483 +  if (!postedExitEvent)
   1.484 +    mShuttingDown = false;
   1.485 +  return rv;
   1.486 +}
   1.487 +
   1.488 +
   1.489 +void
   1.490 +nsAppStartup::CloseAllWindows()
   1.491 +{
   1.492 +  nsCOMPtr<nsIWindowMediator> mediator
   1.493 +    (do_GetService(NS_WINDOWMEDIATOR_CONTRACTID));
   1.494 +
   1.495 +  nsCOMPtr<nsISimpleEnumerator> windowEnumerator;
   1.496 +
   1.497 +  mediator->GetEnumerator(nullptr, getter_AddRefs(windowEnumerator));
   1.498 +
   1.499 +  if (!windowEnumerator)
   1.500 +    return;
   1.501 +
   1.502 +  bool more;
   1.503 +  while (NS_SUCCEEDED(windowEnumerator->HasMoreElements(&more)) && more) {
   1.504 +    nsCOMPtr<nsISupports> isupports;
   1.505 +    if (NS_FAILED(windowEnumerator->GetNext(getter_AddRefs(isupports))))
   1.506 +      break;
   1.507 +
   1.508 +    nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(isupports);
   1.509 +    NS_ASSERTION(window, "not an nsPIDOMWindow");
   1.510 +    if (window)
   1.511 +      window->ForceClose();
   1.512 +  }
   1.513 +}
   1.514 +
   1.515 +NS_IMETHODIMP
   1.516 +nsAppStartup::EnterLastWindowClosingSurvivalArea(void)
   1.517 +{
   1.518 +  ++mConsiderQuitStopper;
   1.519 +  return NS_OK;
   1.520 +}
   1.521 +
   1.522 +
   1.523 +NS_IMETHODIMP
   1.524 +nsAppStartup::ExitLastWindowClosingSurvivalArea(void)
   1.525 +{
   1.526 +  NS_ASSERTION(mConsiderQuitStopper > 0, "consider quit stopper out of bounds");
   1.527 +  --mConsiderQuitStopper;
   1.528 +
   1.529 +  if (mRunning)
   1.530 +    Quit(eConsiderQuit);
   1.531 +
   1.532 +  return NS_OK;
   1.533 +}
   1.534 +
   1.535 +//
   1.536 +// nsAppStartup->nsIAppStartup2
   1.537 +//
   1.538 +
   1.539 +NS_IMETHODIMP
   1.540 +nsAppStartup::GetShuttingDown(bool *aResult)
   1.541 +{
   1.542 +  *aResult = mShuttingDown;
   1.543 +  return NS_OK;
   1.544 +}
   1.545 +
   1.546 +NS_IMETHODIMP
   1.547 +nsAppStartup::GetStartingUp(bool *aResult)
   1.548 +{
   1.549 +  *aResult = mStartingUp;
   1.550 +  return NS_OK;
   1.551 +}
   1.552 +
   1.553 +NS_IMETHODIMP
   1.554 +nsAppStartup::DoneStartingUp()
   1.555 +{
   1.556 +  // This must be called once at most
   1.557 +  MOZ_ASSERT(mStartingUp);
   1.558 +
   1.559 +  mStartingUp = false;
   1.560 +  return NS_OK;
   1.561 +}
   1.562 +
   1.563 +NS_IMETHODIMP
   1.564 +nsAppStartup::GetRestarting(bool *aResult)
   1.565 +{
   1.566 +  *aResult = mRestart;
   1.567 +  return NS_OK;
   1.568 +}
   1.569 +
   1.570 +NS_IMETHODIMP
   1.571 +nsAppStartup::GetWasRestarted(bool *aResult)
   1.572 +{
   1.573 +  char *mozAppRestart = PR_GetEnv("MOZ_APP_RESTART");
   1.574 +
   1.575 +  /* When calling PR_SetEnv() with an empty value the existing variable may
   1.576 +   * be unset or set to the empty string depending on the underlying platform
   1.577 +   * thus we have to check if the variable is present and not empty. */
   1.578 +  *aResult = mozAppRestart && (strcmp(mozAppRestart, "") != 0);
   1.579 +
   1.580 +  return NS_OK;
   1.581 +}
   1.582 +
   1.583 +NS_IMETHODIMP
   1.584 +nsAppStartup::GetRestartingTouchEnvironment(bool *aResult)
   1.585 +{
   1.586 +  NS_ENSURE_ARG_POINTER(aResult);
   1.587 +  *aResult = mRestartTouchEnvironment;
   1.588 +  return NS_OK;
   1.589 +}
   1.590 +
   1.591 +NS_IMETHODIMP
   1.592 +nsAppStartup::SetInterrupted(bool aInterrupted)
   1.593 +{
   1.594 +  mInterrupted = aInterrupted;
   1.595 +  return NS_OK;
   1.596 +}
   1.597 +
   1.598 +NS_IMETHODIMP
   1.599 +nsAppStartup::GetInterrupted(bool *aInterrupted)
   1.600 +{
   1.601 +  *aInterrupted = mInterrupted;
   1.602 +  return NS_OK;
   1.603 +}
   1.604 +
   1.605 +//
   1.606 +// nsAppStartup->nsIWindowCreator
   1.607 +//
   1.608 +
   1.609 +NS_IMETHODIMP
   1.610 +nsAppStartup::CreateChromeWindow(nsIWebBrowserChrome *aParent,
   1.611 +                                 uint32_t aChromeFlags,
   1.612 +                                 nsIWebBrowserChrome **_retval)
   1.613 +{
   1.614 +  bool cancel;
   1.615 +  return CreateChromeWindow2(aParent, aChromeFlags, 0, 0, &cancel, _retval);
   1.616 +}
   1.617 +
   1.618 +
   1.619 +//
   1.620 +// nsAppStartup->nsIWindowCreator2
   1.621 +//
   1.622 +
   1.623 +NS_IMETHODIMP
   1.624 +nsAppStartup::CreateChromeWindow2(nsIWebBrowserChrome *aParent,
   1.625 +                                  uint32_t aChromeFlags,
   1.626 +                                  uint32_t aContextFlags,
   1.627 +                                  nsIURI *aURI,
   1.628 +                                  bool *aCancel,
   1.629 +                                  nsIWebBrowserChrome **_retval)
   1.630 +{
   1.631 +  NS_ENSURE_ARG_POINTER(aCancel);
   1.632 +  NS_ENSURE_ARG_POINTER(_retval);
   1.633 +  *aCancel = false;
   1.634 +  *_retval = 0;
   1.635 +
   1.636 +  // Non-modal windows cannot be opened if we are attempting to quit
   1.637 +  if (mAttemptingQuit && (aChromeFlags & nsIWebBrowserChrome::CHROME_MODAL) == 0)
   1.638 +    return NS_ERROR_ILLEGAL_DURING_SHUTDOWN;
   1.639 +
   1.640 +  nsCOMPtr<nsIXULWindow> newWindow;
   1.641 +
   1.642 +  if (aParent) {
   1.643 +    nsCOMPtr<nsIXULWindow> xulParent(do_GetInterface(aParent));
   1.644 +    NS_ASSERTION(xulParent, "window created using non-XUL parent. that's unexpected, but may work.");
   1.645 +
   1.646 +    if (xulParent)
   1.647 +      xulParent->CreateNewWindow(aChromeFlags, getter_AddRefs(newWindow));
   1.648 +    // And if it fails, don't try again without a parent. It could fail
   1.649 +    // intentionally (bug 115969).
   1.650 +  } else { // try using basic methods:
   1.651 +    /* You really shouldn't be making dependent windows without a parent.
   1.652 +      But unparented modal (and therefore dependent) windows happen
   1.653 +      in our codebase, so we allow it after some bellyaching: */
   1.654 +    if (aChromeFlags & nsIWebBrowserChrome::CHROME_DEPENDENT)
   1.655 +      NS_WARNING("dependent window created without a parent");
   1.656 +
   1.657 +    nsCOMPtr<nsIAppShellService> appShell(do_GetService(NS_APPSHELLSERVICE_CONTRACTID));
   1.658 +    if (!appShell)
   1.659 +      return NS_ERROR_FAILURE;
   1.660 +    
   1.661 +    appShell->CreateTopLevelWindow(0, 0, aChromeFlags,
   1.662 +                                   nsIAppShellService::SIZE_TO_CONTENT,
   1.663 +                                   nsIAppShellService::SIZE_TO_CONTENT,
   1.664 +                                   getter_AddRefs(newWindow));
   1.665 +  }
   1.666 +
   1.667 +  // if anybody gave us anything to work with, use it
   1.668 +  if (newWindow) {
   1.669 +    newWindow->SetContextFlags(aContextFlags);
   1.670 +    nsCOMPtr<nsIInterfaceRequestor> thing(do_QueryInterface(newWindow));
   1.671 +    if (thing)
   1.672 +      CallGetInterface(thing.get(), _retval);
   1.673 +  }
   1.674 +
   1.675 +  return *_retval ? NS_OK : NS_ERROR_FAILURE;
   1.676 +}
   1.677 +
   1.678 +
   1.679 +//
   1.680 +// nsAppStartup->nsIObserver
   1.681 +//
   1.682 +
   1.683 +NS_IMETHODIMP
   1.684 +nsAppStartup::Observe(nsISupports *aSubject,
   1.685 +                      const char *aTopic, const char16_t *aData)
   1.686 +{
   1.687 +  NS_ASSERTION(mAppShell, "appshell service notified before appshell built");
   1.688 +  if (!strcmp(aTopic, "quit-application-forced")) {
   1.689 +    mShuttingDown = true;
   1.690 +  }
   1.691 +  else if (!strcmp(aTopic, "profile-change-teardown")) {
   1.692 +    if (!mShuttingDown) {
   1.693 +      EnterLastWindowClosingSurvivalArea();
   1.694 +      CloseAllWindows();
   1.695 +      ExitLastWindowClosingSurvivalArea();
   1.696 +    }
   1.697 +  } else if (!strcmp(aTopic, "xul-window-registered")) {
   1.698 +    EnterLastWindowClosingSurvivalArea();
   1.699 +  } else if (!strcmp(aTopic, "xul-window-destroyed")) {
   1.700 +    ExitLastWindowClosingSurvivalArea();
   1.701 +  } else if (!strcmp(aTopic, "sessionstore-windows-restored")) {
   1.702 +    StartupTimeline::Record(StartupTimeline::SESSION_RESTORED);
   1.703 +    IOInterposer::EnteringNextStage();
   1.704 +#if defined(XP_WIN)
   1.705 +    if (mSessionWindowRestoredProbe) {
   1.706 +      mSessionWindowRestoredProbe->Trigger();
   1.707 +    }
   1.708 +  } else if (!strcmp(aTopic, "places-init-complete")) {
   1.709 +    if (mPlacesInitCompleteProbe) {
   1.710 +      mPlacesInitCompleteProbe->Trigger();
   1.711 +    }
   1.712 +#endif //defined(XP_WIN)
   1.713 +  } else if (!strcmp(aTopic, "sessionstore-init-started")) {
   1.714 +    StartupTimeline::Record(StartupTimeline::SESSION_RESTORE_INIT);
   1.715 +  } else if (!strcmp(aTopic, "xpcom-shutdown")) {
   1.716 +    IOInterposer::EnteringNextStage();
   1.717 +#if defined(XP_WIN)
   1.718 +    if (mXPCOMShutdownProbe) {
   1.719 +      mXPCOMShutdownProbe->Trigger();
   1.720 +    }
   1.721 +#endif // defined(XP_WIN)
   1.722 +  } else {
   1.723 +    NS_ERROR("Unexpected observer topic.");
   1.724 +  }
   1.725 +
   1.726 +  return NS_OK;
   1.727 +}
   1.728 +
   1.729 +NS_IMETHODIMP
   1.730 +nsAppStartup::GetStartupInfo(JSContext* aCx, JS::MutableHandle<JS::Value> aRetval)
   1.731 +{
   1.732 +  JS::Rooted<JSObject*> obj(aCx, JS_NewObject(aCx, nullptr, JS::NullPtr(), JS::NullPtr()));
   1.733 +
   1.734 +  aRetval.setObject(*obj);
   1.735 +
   1.736 +  TimeStamp procTime = StartupTimeline::Get(StartupTimeline::PROCESS_CREATION);
   1.737 +  TimeStamp now = TimeStamp::Now();
   1.738 +  PRTime absNow = PR_Now();
   1.739 +
   1.740 +  if (procTime.IsNull()) {
   1.741 +    bool error = false;
   1.742 +
   1.743 +    procTime = TimeStamp::ProcessCreation(error);
   1.744 +
   1.745 +    if (error) {
   1.746 +      Telemetry::Accumulate(Telemetry::STARTUP_MEASUREMENT_ERRORS,
   1.747 +        StartupTimeline::PROCESS_CREATION);
   1.748 +    }
   1.749 +
   1.750 +    StartupTimeline::Record(StartupTimeline::PROCESS_CREATION, procTime);
   1.751 +  }
   1.752 +
   1.753 +  for (int i = StartupTimeline::PROCESS_CREATION;
   1.754 +       i < StartupTimeline::MAX_EVENT_ID;
   1.755 +       ++i)
   1.756 +  {
   1.757 +    StartupTimeline::Event ev = static_cast<StartupTimeline::Event>(i);
   1.758 +    TimeStamp stamp = StartupTimeline::Get(ev);
   1.759 +
   1.760 +    if (stamp.IsNull() && (ev == StartupTimeline::MAIN)) {
   1.761 +      // Always define main to aid with bug 689256.
   1.762 +      stamp = procTime;
   1.763 +      MOZ_ASSERT(!stamp.IsNull());
   1.764 +      Telemetry::Accumulate(Telemetry::STARTUP_MEASUREMENT_ERRORS,
   1.765 +        StartupTimeline::MAIN);
   1.766 +    }
   1.767 +
   1.768 +    if (!stamp.IsNull()) {
   1.769 +      if (stamp >= procTime) {
   1.770 +        PRTime prStamp = ComputeAbsoluteTimestamp(absNow, now, stamp)
   1.771 +          / PR_USEC_PER_MSEC;
   1.772 +        JS::Rooted<JSObject*> date(aCx, JS_NewDateObjectMsec(aCx, prStamp));
   1.773 +        JS_DefineProperty(aCx, obj, StartupTimeline::Describe(ev), date, JSPROP_ENUMERATE);
   1.774 +      } else {
   1.775 +        Telemetry::Accumulate(Telemetry::STARTUP_MEASUREMENT_ERRORS, ev);
   1.776 +      }
   1.777 +    }
   1.778 +  }
   1.779 +
   1.780 +  return NS_OK;
   1.781 +}
   1.782 +
   1.783 +NS_IMETHODIMP
   1.784 +nsAppStartup::GetAutomaticSafeModeNecessary(bool *_retval)
   1.785 +{
   1.786 +  NS_ENSURE_ARG_POINTER(_retval);
   1.787 +
   1.788 +  bool alwaysSafe = false;
   1.789 +  Preferences::GetBool(kPrefAlwaysUseSafeMode, &alwaysSafe);
   1.790 +
   1.791 +  if (!alwaysSafe) {
   1.792 +#if DEBUG
   1.793 +    mIsSafeModeNecessary = false;
   1.794 +#else
   1.795 +    mIsSafeModeNecessary &= !PR_GetEnv("MOZ_DISABLE_AUTO_SAFE_MODE");
   1.796 +#endif
   1.797 +  }
   1.798 +
   1.799 +  *_retval = mIsSafeModeNecessary;
   1.800 +  return NS_OK;
   1.801 +}
   1.802 +
   1.803 +NS_IMETHODIMP
   1.804 +nsAppStartup::TrackStartupCrashBegin(bool *aIsSafeModeNecessary)
   1.805 +{
   1.806 +  const int32_t MAX_TIME_SINCE_STARTUP = 6 * 60 * 60 * 1000;
   1.807 +  const int32_t MAX_STARTUP_BUFFER = 10;
   1.808 +  nsresult rv;
   1.809 +
   1.810 +  mStartupCrashTrackingEnded = false;
   1.811 +
   1.812 +  StartupTimeline::Record(StartupTimeline::STARTUP_CRASH_DETECTION_BEGIN);
   1.813 +
   1.814 +  bool hasLastSuccess = Preferences::HasUserValue(kPrefLastSuccess);
   1.815 +  if (!hasLastSuccess) {
   1.816 +    // Clear so we don't get stuck with SafeModeNecessary returning true if we
   1.817 +    // have had too many recent crashes and the last success pref is missing.
   1.818 +    Preferences::ClearUser(kPrefRecentCrashes);
   1.819 +    return NS_ERROR_NOT_AVAILABLE;
   1.820 +  }
   1.821 +
   1.822 +  bool inSafeMode = false;
   1.823 +  nsCOMPtr<nsIXULRuntime> xr = do_GetService(XULRUNTIME_SERVICE_CONTRACTID);
   1.824 +  NS_ENSURE_TRUE(xr, NS_ERROR_FAILURE);
   1.825 +
   1.826 +  xr->GetInSafeMode(&inSafeMode);
   1.827 +
   1.828 +  PRTime replacedLockTime;
   1.829 +  rv = xr->GetReplacedLockTime(&replacedLockTime);
   1.830 +
   1.831 +  if (NS_FAILED(rv) || !replacedLockTime) {
   1.832 +    if (!inSafeMode)
   1.833 +      Preferences::ClearUser(kPrefRecentCrashes);
   1.834 +    GetAutomaticSafeModeNecessary(aIsSafeModeNecessary);
   1.835 +    return NS_OK;
   1.836 +  }
   1.837 +
   1.838 +  // check whether safe mode is necessary
   1.839 +  int32_t maxResumedCrashes = -1;
   1.840 +  rv = Preferences::GetInt(kPrefMaxResumedCrashes, &maxResumedCrashes);
   1.841 +  NS_ENSURE_SUCCESS(rv, NS_OK);
   1.842 +
   1.843 +  int32_t recentCrashes = 0;
   1.844 +  Preferences::GetInt(kPrefRecentCrashes, &recentCrashes);
   1.845 +  mIsSafeModeNecessary = (recentCrashes > maxResumedCrashes && maxResumedCrashes != -1);
   1.846 +
   1.847 +  // Bug 731613 - Don't check if the last startup was a crash if XRE_PROFILE_PATH is set.  After
   1.848 +  // profile manager, the profile lock's mod. time has been changed so can't be used on this startup.
   1.849 +  // After a restart, it's safe to assume the last startup was successful.
   1.850 +  char *xreProfilePath = PR_GetEnv("XRE_PROFILE_PATH");
   1.851 +  if (xreProfilePath) {
   1.852 +    GetAutomaticSafeModeNecessary(aIsSafeModeNecessary);
   1.853 +    return NS_ERROR_NOT_AVAILABLE;
   1.854 +  }
   1.855 +
   1.856 +  // time of last successful startup
   1.857 +  int32_t lastSuccessfulStartup;
   1.858 +  rv = Preferences::GetInt(kPrefLastSuccess, &lastSuccessfulStartup);
   1.859 +  NS_ENSURE_SUCCESS(rv, rv);
   1.860 +
   1.861 +  int32_t lockSeconds = (int32_t)(replacedLockTime / PR_MSEC_PER_SEC);
   1.862 +
   1.863 +  // started close enough to good startup so call it good
   1.864 +  if (lockSeconds <= lastSuccessfulStartup + MAX_STARTUP_BUFFER
   1.865 +      && lockSeconds >= lastSuccessfulStartup - MAX_STARTUP_BUFFER) {
   1.866 +    GetAutomaticSafeModeNecessary(aIsSafeModeNecessary);
   1.867 +    return NS_OK;
   1.868 +  }
   1.869 +
   1.870 +  // sanity check that the pref set at last success is not greater than the current time
   1.871 +  if (PR_Now() / PR_USEC_PER_SEC <= lastSuccessfulStartup)
   1.872 +    return NS_ERROR_FAILURE;
   1.873 +
   1.874 +  // The last startup was a crash so include it in the count regardless of when it happened.
   1.875 +  Telemetry::Accumulate(Telemetry::STARTUP_CRASH_DETECTED, true);
   1.876 +
   1.877 +  if (inSafeMode) {
   1.878 +    GetAutomaticSafeModeNecessary(aIsSafeModeNecessary);
   1.879 +    return NS_OK;
   1.880 +  }
   1.881 +
   1.882 +  PRTime now = (PR_Now() / PR_USEC_PER_MSEC);
   1.883 +  // if the last startup attempt which crashed was in the last 6 hours
   1.884 +  if (replacedLockTime >= now - MAX_TIME_SINCE_STARTUP) {
   1.885 +    NS_WARNING("Last startup was detected as a crash.");
   1.886 +    recentCrashes++;
   1.887 +    rv = Preferences::SetInt(kPrefRecentCrashes, recentCrashes);
   1.888 +  } else {
   1.889 +    // Otherwise ignore that crash and all previous since it may not be applicable anymore
   1.890 +    // and we don't want someone to get stuck in safe mode if their prefs are read-only.
   1.891 +    rv = Preferences::ClearUser(kPrefRecentCrashes);
   1.892 +  }
   1.893 +  NS_ENSURE_SUCCESS(rv, rv);
   1.894 +
   1.895 +  // recalculate since recent crashes count may have changed above
   1.896 +  mIsSafeModeNecessary = (recentCrashes > maxResumedCrashes && maxResumedCrashes != -1);
   1.897 +
   1.898 +  nsCOMPtr<nsIPrefService> prefs = Preferences::GetService();
   1.899 +  rv = prefs->SavePrefFile(nullptr); // flush prefs to disk since we are tracking crashes
   1.900 +  NS_ENSURE_SUCCESS(rv, rv);
   1.901 +
   1.902 +  GetAutomaticSafeModeNecessary(aIsSafeModeNecessary);
   1.903 +  return rv;
   1.904 +}
   1.905 +
   1.906 +NS_IMETHODIMP
   1.907 +nsAppStartup::TrackStartupCrashEnd()
   1.908 +{
   1.909 +  bool inSafeMode = false;
   1.910 +  nsCOMPtr<nsIXULRuntime> xr = do_GetService(XULRUNTIME_SERVICE_CONTRACTID);
   1.911 +  if (xr)
   1.912 +    xr->GetInSafeMode(&inSafeMode);
   1.913 +
   1.914 +  // return if we already ended or we're restarting into safe mode
   1.915 +  if (mStartupCrashTrackingEnded || (mIsSafeModeNecessary && !inSafeMode))
   1.916 +    return NS_OK;
   1.917 +  mStartupCrashTrackingEnded = true;
   1.918 +
   1.919 +  StartupTimeline::Record(StartupTimeline::STARTUP_CRASH_DETECTION_END);
   1.920 +
   1.921 +  // Use the timestamp of XRE_main as an approximation for the lock file timestamp.
   1.922 +  // See MAX_STARTUP_BUFFER for the buffer time period.
   1.923 +  TimeStamp mainTime = StartupTimeline::Get(StartupTimeline::MAIN);
   1.924 +  TimeStamp now = TimeStamp::Now();
   1.925 +  PRTime prNow = PR_Now();
   1.926 +  nsresult rv;
   1.927 +
   1.928 +  if (mainTime.IsNull()) {
   1.929 +    NS_WARNING("Could not get StartupTimeline::MAIN time.");
   1.930 +  } else {
   1.931 +    uint64_t lockFileTime = ComputeAbsoluteTimestamp(prNow, now, mainTime);
   1.932 +
   1.933 +    rv = Preferences::SetInt(kPrefLastSuccess,
   1.934 +      (int32_t)(lockFileTime / PR_USEC_PER_SEC));
   1.935 +
   1.936 +    if (NS_FAILED(rv))
   1.937 +      NS_WARNING("Could not set startup crash detection pref.");
   1.938 +  }
   1.939 +
   1.940 +  if (inSafeMode && mIsSafeModeNecessary) {
   1.941 +    // On a successful startup in automatic safe mode, allow the user one more crash
   1.942 +    // in regular mode before returning to safe mode.
   1.943 +    int32_t maxResumedCrashes = 0;
   1.944 +    int32_t prefType;
   1.945 +    rv = Preferences::GetDefaultRootBranch()->GetPrefType(kPrefMaxResumedCrashes, &prefType);
   1.946 +    NS_ENSURE_SUCCESS(rv, rv);
   1.947 +    if (prefType == nsIPrefBranch::PREF_INT) {
   1.948 +      rv = Preferences::GetInt(kPrefMaxResumedCrashes, &maxResumedCrashes);
   1.949 +      NS_ENSURE_SUCCESS(rv, rv);
   1.950 +    }
   1.951 +    rv = Preferences::SetInt(kPrefRecentCrashes, maxResumedCrashes);
   1.952 +    NS_ENSURE_SUCCESS(rv, rv);
   1.953 +  } else if (!inSafeMode) {
   1.954 +    // clear the count of recent crashes after a succesful startup when not in safe mode
   1.955 +    rv = Preferences::ClearUser(kPrefRecentCrashes);
   1.956 +    if (NS_FAILED(rv)) NS_WARNING("Could not clear startup crash count.");
   1.957 +  }
   1.958 +  nsCOMPtr<nsIPrefService> prefs = Preferences::GetService();
   1.959 +  rv = prefs->SavePrefFile(nullptr); // flush prefs to disk since we are tracking crashes
   1.960 +
   1.961 +  return rv;
   1.962 +}
   1.963 +
   1.964 +NS_IMETHODIMP
   1.965 +nsAppStartup::RestartInSafeMode(uint32_t aQuitMode)
   1.966 +{
   1.967 +  PR_SetEnv("MOZ_SAFE_MODE_RESTART=1");
   1.968 +  this->Quit(aQuitMode | nsIAppStartup::eRestart);
   1.969 +
   1.970 +  return NS_OK;
   1.971 +}

mercurial