toolkit/components/startup/nsAppStartup.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #include "nsAppStartup.h"
michael@0 7
michael@0 8 #include "nsIAppShellService.h"
michael@0 9 #include "nsPIDOMWindow.h"
michael@0 10 #include "nsIInterfaceRequestor.h"
michael@0 11 #include "nsIFile.h"
michael@0 12 #include "nsIObserverService.h"
michael@0 13 #include "nsIPrefBranch.h"
michael@0 14 #include "nsIPrefService.h"
michael@0 15 #include "nsIPromptService.h"
michael@0 16 #include "nsIStringBundle.h"
michael@0 17 #include "nsISupportsPrimitives.h"
michael@0 18 #include "nsIWebBrowserChrome.h"
michael@0 19 #include "nsIWindowMediator.h"
michael@0 20 #include "nsIWindowWatcher.h"
michael@0 21 #include "nsIXULRuntime.h"
michael@0 22 #include "nsIXULWindow.h"
michael@0 23 #include "nsNativeCharsetUtils.h"
michael@0 24 #include "nsThreadUtils.h"
michael@0 25 #include "nsAutoPtr.h"
michael@0 26 #include "nsString.h"
michael@0 27 #include "mozilla/Preferences.h"
michael@0 28 #include "GeckoProfiler.h"
michael@0 29
michael@0 30 #include "prprf.h"
michael@0 31 #include "nsIInterfaceRequestorUtils.h"
michael@0 32 #include "nsWidgetsCID.h"
michael@0 33 #include "nsAppShellCID.h"
michael@0 34 #include "nsXPCOMCIDInternal.h"
michael@0 35 #include "mozilla/Services.h"
michael@0 36 #include "nsIXPConnect.h"
michael@0 37 #include "jsapi.h"
michael@0 38 #include "prenv.h"
michael@0 39 #include "nsAppDirectoryServiceDefs.h"
michael@0 40
michael@0 41 #if defined(XP_WIN)
michael@0 42 // Prevent collisions with nsAppStartup::GetStartupInfo()
michael@0 43 #undef GetStartupInfo
michael@0 44 #endif
michael@0 45
michael@0 46 #include "mozilla/IOInterposer.h"
michael@0 47 #include "mozilla/Telemetry.h"
michael@0 48 #include "mozilla/StartupTimeline.h"
michael@0 49
michael@0 50 static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
michael@0 51
michael@0 52 #define kPrefLastSuccess "toolkit.startup.last_success"
michael@0 53 #define kPrefMaxResumedCrashes "toolkit.startup.max_resumed_crashes"
michael@0 54 #define kPrefRecentCrashes "toolkit.startup.recent_crashes"
michael@0 55 #define kPrefAlwaysUseSafeMode "toolkit.startup.always_use_safe_mode"
michael@0 56
michael@0 57 #if defined(XP_WIN)
michael@0 58 #include "mozilla/perfprobe.h"
michael@0 59 /**
michael@0 60 * Events sent to the system for profiling purposes
michael@0 61 */
michael@0 62 //Keep them syncronized with the .mof file
michael@0 63
michael@0 64 //Process-wide GUID, used by the OS to differentiate sources
michael@0 65 // {509962E0-406B-46F4-99BA-5A009F8D2225}
michael@0 66 //Keep it synchronized with the .mof file
michael@0 67 #define NS_APPLICATION_TRACING_CID \
michael@0 68 { 0x509962E0, 0x406B, 0x46F4, \
michael@0 69 { 0x99, 0xBA, 0x5A, 0x00, 0x9F, 0x8D, 0x22, 0x25} }
michael@0 70
michael@0 71 //Event-specific GUIDs, used by the OS to differentiate events
michael@0 72 // {A3DA04E0-57D7-482A-A1C1-61DA5F95BACB}
michael@0 73 #define NS_PLACES_INIT_COMPLETE_EVENT_CID \
michael@0 74 { 0xA3DA04E0, 0x57D7, 0x482A, \
michael@0 75 { 0xA1, 0xC1, 0x61, 0xDA, 0x5F, 0x95, 0xBA, 0xCB} }
michael@0 76 // {917B96B1-ECAD-4DAB-A760-8D49027748AE}
michael@0 77 #define NS_SESSION_STORE_WINDOW_RESTORED_EVENT_CID \
michael@0 78 { 0x917B96B1, 0xECAD, 0x4DAB, \
michael@0 79 { 0xA7, 0x60, 0x8D, 0x49, 0x02, 0x77, 0x48, 0xAE} }
michael@0 80 // {26D1E091-0AE7-4F49-A554-4214445C505C}
michael@0 81 #define NS_XPCOM_SHUTDOWN_EVENT_CID \
michael@0 82 { 0x26D1E091, 0x0AE7, 0x4F49, \
michael@0 83 { 0xA5, 0x54, 0x42, 0x14, 0x44, 0x5C, 0x50, 0x5C} }
michael@0 84
michael@0 85 static NS_DEFINE_CID(kApplicationTracingCID,
michael@0 86 NS_APPLICATION_TRACING_CID);
michael@0 87 static NS_DEFINE_CID(kPlacesInitCompleteCID,
michael@0 88 NS_PLACES_INIT_COMPLETE_EVENT_CID);
michael@0 89 static NS_DEFINE_CID(kSessionStoreWindowRestoredCID,
michael@0 90 NS_SESSION_STORE_WINDOW_RESTORED_EVENT_CID);
michael@0 91 static NS_DEFINE_CID(kXPCOMShutdownCID,
michael@0 92 NS_XPCOM_SHUTDOWN_EVENT_CID);
michael@0 93 #endif //defined(XP_WIN)
michael@0 94
michael@0 95 using namespace mozilla;
michael@0 96
michael@0 97 uint32_t gRestartMode = 0;
michael@0 98
michael@0 99 class nsAppExitEvent : public nsRunnable {
michael@0 100 private:
michael@0 101 nsRefPtr<nsAppStartup> mService;
michael@0 102
michael@0 103 public:
michael@0 104 nsAppExitEvent(nsAppStartup *service) : mService(service) {}
michael@0 105
michael@0 106 NS_IMETHOD Run() {
michael@0 107 // Tell the appshell to exit
michael@0 108 mService->mAppShell->Exit();
michael@0 109
michael@0 110 mService->mRunning = false;
michael@0 111 return NS_OK;
michael@0 112 }
michael@0 113 };
michael@0 114
michael@0 115 /**
michael@0 116 * Computes an approximation of the absolute time represented by @a stamp
michael@0 117 * which is comparable to those obtained via PR_Now(). If the current absolute
michael@0 118 * time varies a lot (e.g. DST adjustments) since the first call then the
michael@0 119 * resulting times may be inconsistent.
michael@0 120 *
michael@0 121 * @param stamp The timestamp to be converted
michael@0 122 * @returns The converted timestamp
michael@0 123 */
michael@0 124 uint64_t ComputeAbsoluteTimestamp(PRTime prnow, TimeStamp now, TimeStamp stamp)
michael@0 125 {
michael@0 126 static PRTime sAbsoluteNow = PR_Now();
michael@0 127 static TimeStamp sMonotonicNow = TimeStamp::Now();
michael@0 128
michael@0 129 return sAbsoluteNow - (sMonotonicNow - stamp).ToMicroseconds();
michael@0 130 }
michael@0 131
michael@0 132 //
michael@0 133 // nsAppStartup
michael@0 134 //
michael@0 135
michael@0 136 nsAppStartup::nsAppStartup() :
michael@0 137 mConsiderQuitStopper(0),
michael@0 138 mRunning(false),
michael@0 139 mShuttingDown(false),
michael@0 140 mStartingUp(true),
michael@0 141 mAttemptingQuit(false),
michael@0 142 mRestart(false),
michael@0 143 mInterrupted(false),
michael@0 144 mIsSafeModeNecessary(false),
michael@0 145 mStartupCrashTrackingEnded(false),
michael@0 146 mRestartTouchEnvironment(false)
michael@0 147 { }
michael@0 148
michael@0 149
michael@0 150 nsresult
michael@0 151 nsAppStartup::Init()
michael@0 152 {
michael@0 153 nsresult rv;
michael@0 154
michael@0 155 // Create widget application shell
michael@0 156 mAppShell = do_GetService(kAppShellCID, &rv);
michael@0 157 NS_ENSURE_SUCCESS(rv, rv);
michael@0 158
michael@0 159 nsCOMPtr<nsIObserverService> os =
michael@0 160 mozilla::services::GetObserverService();
michael@0 161 if (!os)
michael@0 162 return NS_ERROR_FAILURE;
michael@0 163
michael@0 164 os->AddObserver(this, "quit-application-forced", true);
michael@0 165 os->AddObserver(this, "sessionstore-init-started", true);
michael@0 166 os->AddObserver(this, "sessionstore-windows-restored", true);
michael@0 167 os->AddObserver(this, "profile-change-teardown", true);
michael@0 168 os->AddObserver(this, "xul-window-registered", true);
michael@0 169 os->AddObserver(this, "xul-window-destroyed", true);
michael@0 170 os->AddObserver(this, "xpcom-shutdown", true);
michael@0 171
michael@0 172 #if defined(XP_WIN)
michael@0 173 os->AddObserver(this, "places-init-complete", true);
michael@0 174 // This last event is only interesting to us for xperf-based measures
michael@0 175
michael@0 176 // Initialize interaction with profiler
michael@0 177 mProbesManager =
michael@0 178 new ProbeManager(
michael@0 179 kApplicationTracingCID,
michael@0 180 NS_LITERAL_CSTRING("Application startup probe"));
michael@0 181 // Note: The operation is meant mostly for in-house profiling.
michael@0 182 // Therefore, we do not warn if probes manager cannot be initialized
michael@0 183
michael@0 184 if (mProbesManager) {
michael@0 185 mPlacesInitCompleteProbe =
michael@0 186 mProbesManager->
michael@0 187 GetProbe(kPlacesInitCompleteCID,
michael@0 188 NS_LITERAL_CSTRING("places-init-complete"));
michael@0 189 NS_WARN_IF_FALSE(mPlacesInitCompleteProbe,
michael@0 190 "Cannot initialize probe 'places-init-complete'");
michael@0 191
michael@0 192 mSessionWindowRestoredProbe =
michael@0 193 mProbesManager->
michael@0 194 GetProbe(kSessionStoreWindowRestoredCID,
michael@0 195 NS_LITERAL_CSTRING("sessionstore-windows-restored"));
michael@0 196 NS_WARN_IF_FALSE(mSessionWindowRestoredProbe,
michael@0 197 "Cannot initialize probe 'sessionstore-windows-restored'");
michael@0 198
michael@0 199 mXPCOMShutdownProbe =
michael@0 200 mProbesManager->
michael@0 201 GetProbe(kXPCOMShutdownCID,
michael@0 202 NS_LITERAL_CSTRING("xpcom-shutdown"));
michael@0 203 NS_WARN_IF_FALSE(mXPCOMShutdownProbe,
michael@0 204 "Cannot initialize probe 'xpcom-shutdown'");
michael@0 205
michael@0 206 rv = mProbesManager->StartSession();
michael@0 207 NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
michael@0 208 "Cannot initialize system probe manager");
michael@0 209 }
michael@0 210 #endif //defined(XP_WIN)
michael@0 211
michael@0 212 return NS_OK;
michael@0 213 }
michael@0 214
michael@0 215
michael@0 216 //
michael@0 217 // nsAppStartup->nsISupports
michael@0 218 //
michael@0 219
michael@0 220 NS_IMPL_ISUPPORTS(nsAppStartup,
michael@0 221 nsIAppStartup,
michael@0 222 nsIWindowCreator,
michael@0 223 nsIWindowCreator2,
michael@0 224 nsIObserver,
michael@0 225 nsISupportsWeakReference)
michael@0 226
michael@0 227
michael@0 228 //
michael@0 229 // nsAppStartup->nsIAppStartup
michael@0 230 //
michael@0 231
michael@0 232 NS_IMETHODIMP
michael@0 233 nsAppStartup::CreateHiddenWindow()
michael@0 234 {
michael@0 235 #ifdef MOZ_WIDGET_GONK
michael@0 236 return NS_OK;
michael@0 237 #else
michael@0 238 nsCOMPtr<nsIAppShellService> appShellService
michael@0 239 (do_GetService(NS_APPSHELLSERVICE_CONTRACTID));
michael@0 240 NS_ENSURE_TRUE(appShellService, NS_ERROR_FAILURE);
michael@0 241
michael@0 242 return appShellService->CreateHiddenWindow();
michael@0 243 #endif
michael@0 244 }
michael@0 245
michael@0 246
michael@0 247 NS_IMETHODIMP
michael@0 248 nsAppStartup::DestroyHiddenWindow()
michael@0 249 {
michael@0 250 #ifdef MOZ_WIDGET_GONK
michael@0 251 return NS_OK;
michael@0 252 #else
michael@0 253 nsCOMPtr<nsIAppShellService> appShellService
michael@0 254 (do_GetService(NS_APPSHELLSERVICE_CONTRACTID));
michael@0 255 NS_ENSURE_TRUE(appShellService, NS_ERROR_FAILURE);
michael@0 256
michael@0 257 return appShellService->DestroyHiddenWindow();
michael@0 258 #endif
michael@0 259 }
michael@0 260
michael@0 261 NS_IMETHODIMP
michael@0 262 nsAppStartup::Run(void)
michael@0 263 {
michael@0 264 NS_ASSERTION(!mRunning, "Reentrant appstartup->Run()");
michael@0 265
michael@0 266 // If we have no windows open and no explicit calls to
michael@0 267 // enterLastWindowClosingSurvivalArea, or somebody has explicitly called
michael@0 268 // quit, don't bother running the event loop which would probably leave us
michael@0 269 // with a zombie process.
michael@0 270
michael@0 271 if (!mShuttingDown && mConsiderQuitStopper != 0) {
michael@0 272 #ifdef XP_MACOSX
michael@0 273 EnterLastWindowClosingSurvivalArea();
michael@0 274 #endif
michael@0 275
michael@0 276 mRunning = true;
michael@0 277
michael@0 278 nsresult rv = mAppShell->Run();
michael@0 279 if (NS_FAILED(rv))
michael@0 280 return rv;
michael@0 281 }
michael@0 282
michael@0 283 nsresult retval = NS_OK;
michael@0 284 if (mRestartTouchEnvironment) {
michael@0 285 retval = NS_SUCCESS_RESTART_METRO_APP;
michael@0 286 } else if (mRestart) {
michael@0 287 retval = NS_SUCCESS_RESTART_APP;
michael@0 288 }
michael@0 289
michael@0 290 return retval;
michael@0 291 }
michael@0 292
michael@0 293
michael@0 294
michael@0 295 NS_IMETHODIMP
michael@0 296 nsAppStartup::Quit(uint32_t aMode)
michael@0 297 {
michael@0 298 uint32_t ferocity = (aMode & 0xF);
michael@0 299
michael@0 300 // Quit the application. We will asynchronously call the appshell's
michael@0 301 // Exit() method via nsAppExitEvent to allow one last pass
michael@0 302 // through any events in the queue. This guarantees a tidy cleanup.
michael@0 303 nsresult rv = NS_OK;
michael@0 304 bool postedExitEvent = false;
michael@0 305
michael@0 306 if (mShuttingDown)
michael@0 307 return NS_OK;
michael@0 308
michael@0 309 // If we're considering quitting, we will only do so if:
michael@0 310 if (ferocity == eConsiderQuit) {
michael@0 311 #ifdef XP_MACOSX
michael@0 312 nsCOMPtr<nsIAppShellService> appShell
michael@0 313 (do_GetService(NS_APPSHELLSERVICE_CONTRACTID));
michael@0 314 bool hasHiddenPrivateWindow = false;
michael@0 315 if (appShell) {
michael@0 316 appShell->GetHasHiddenPrivateWindow(&hasHiddenPrivateWindow);
michael@0 317 }
michael@0 318 int32_t suspiciousCount = hasHiddenPrivateWindow ? 2 : 1;
michael@0 319 #endif
michael@0 320
michael@0 321 if (mConsiderQuitStopper == 0) {
michael@0 322 // there are no windows...
michael@0 323 ferocity = eAttemptQuit;
michael@0 324 }
michael@0 325 #ifdef XP_MACOSX
michael@0 326 else if (mConsiderQuitStopper == suspiciousCount) {
michael@0 327 // ... or there is only a hiddenWindow left, and it's useless:
michael@0 328
michael@0 329 // Failure shouldn't be fatal, but will abort quit attempt:
michael@0 330 if (!appShell)
michael@0 331 return NS_OK;
michael@0 332
michael@0 333 bool usefulHiddenWindow;
michael@0 334 appShell->GetApplicationProvidedHiddenWindow(&usefulHiddenWindow);
michael@0 335 nsCOMPtr<nsIXULWindow> hiddenWindow;
michael@0 336 appShell->GetHiddenWindow(getter_AddRefs(hiddenWindow));
michael@0 337 // If the remaining windows are useful, we won't quit:
michael@0 338 nsCOMPtr<nsIXULWindow> hiddenPrivateWindow;
michael@0 339 if (hasHiddenPrivateWindow) {
michael@0 340 appShell->GetHiddenPrivateWindow(getter_AddRefs(hiddenPrivateWindow));
michael@0 341 if ((!hiddenWindow && !hiddenPrivateWindow) || usefulHiddenWindow)
michael@0 342 return NS_OK;
michael@0 343 } else if (!hiddenWindow || usefulHiddenWindow) {
michael@0 344 return NS_OK;
michael@0 345 }
michael@0 346
michael@0 347 ferocity = eAttemptQuit;
michael@0 348 }
michael@0 349 #endif
michael@0 350 }
michael@0 351
michael@0 352 nsCOMPtr<nsIObserverService> obsService;
michael@0 353 if (ferocity == eAttemptQuit || ferocity == eForceQuit) {
michael@0 354
michael@0 355 nsCOMPtr<nsISimpleEnumerator> windowEnumerator;
michael@0 356 nsCOMPtr<nsIWindowMediator> mediator (do_GetService(NS_WINDOWMEDIATOR_CONTRACTID));
michael@0 357 if (mediator) {
michael@0 358 mediator->GetEnumerator(nullptr, getter_AddRefs(windowEnumerator));
michael@0 359 if (windowEnumerator) {
michael@0 360 bool more;
michael@0 361 while (windowEnumerator->HasMoreElements(&more), more) {
michael@0 362 nsCOMPtr<nsISupports> window;
michael@0 363 windowEnumerator->GetNext(getter_AddRefs(window));
michael@0 364 nsCOMPtr<nsPIDOMWindow> domWindow(do_QueryInterface(window));
michael@0 365 if (domWindow) {
michael@0 366 if (!domWindow->CanClose())
michael@0 367 return NS_OK;
michael@0 368 }
michael@0 369 }
michael@0 370 }
michael@0 371 }
michael@0 372
michael@0 373 PROFILER_MARKER("Shutdown start");
michael@0 374 mozilla::RecordShutdownStartTimeStamp();
michael@0 375 mShuttingDown = true;
michael@0 376 if (!mRestart) {
michael@0 377 mRestart = (aMode & eRestart) != 0;
michael@0 378 gRestartMode = (aMode & 0xF0);
michael@0 379 }
michael@0 380
michael@0 381 if (!mRestartTouchEnvironment) {
michael@0 382 mRestartTouchEnvironment = (aMode & eRestartTouchEnvironment) != 0;
michael@0 383 gRestartMode = (aMode & 0xF0);
michael@0 384 }
michael@0 385
michael@0 386 if (mRestart || mRestartTouchEnvironment) {
michael@0 387 // Mark the next startup as a restart.
michael@0 388 PR_SetEnv("MOZ_APP_RESTART=1");
michael@0 389
michael@0 390 /* Firefox-restarts reuse the process so regular process start-time isn't
michael@0 391 a useful indicator of startup time anymore. */
michael@0 392 TimeStamp::RecordProcessRestart();
michael@0 393 }
michael@0 394
michael@0 395 obsService = mozilla::services::GetObserverService();
michael@0 396
michael@0 397 if (!mAttemptingQuit) {
michael@0 398 mAttemptingQuit = true;
michael@0 399 #ifdef XP_MACOSX
michael@0 400 // now even the Mac wants to quit when the last window is closed
michael@0 401 ExitLastWindowClosingSurvivalArea();
michael@0 402 #endif
michael@0 403 if (obsService)
michael@0 404 obsService->NotifyObservers(nullptr, "quit-application-granted", nullptr);
michael@0 405 }
michael@0 406
michael@0 407 /* Enumerate through each open window and close it. It's important to do
michael@0 408 this before we forcequit because this can control whether we really quit
michael@0 409 at all. e.g. if one of these windows has an unload handler that
michael@0 410 opens a new window. Ugh. I know. */
michael@0 411 CloseAllWindows();
michael@0 412
michael@0 413 if (mediator) {
michael@0 414 if (ferocity == eAttemptQuit) {
michael@0 415 ferocity = eForceQuit; // assume success
michael@0 416
michael@0 417 /* Were we able to immediately close all windows? if not, eAttemptQuit
michael@0 418 failed. This could happen for a variety of reasons; in fact it's
michael@0 419 very likely. Perhaps we're being called from JS and the window->Close
michael@0 420 method hasn't had a chance to wrap itself up yet. So give up.
michael@0 421 We'll return (with eConsiderQuit) as the remaining windows are
michael@0 422 closed. */
michael@0 423 mediator->GetEnumerator(nullptr, getter_AddRefs(windowEnumerator));
michael@0 424 if (windowEnumerator) {
michael@0 425 bool more;
michael@0 426 while (windowEnumerator->HasMoreElements(&more), more) {
michael@0 427 /* we can't quit immediately. we'll try again as the last window
michael@0 428 finally closes. */
michael@0 429 ferocity = eAttemptQuit;
michael@0 430 nsCOMPtr<nsISupports> window;
michael@0 431 windowEnumerator->GetNext(getter_AddRefs(window));
michael@0 432 nsCOMPtr<nsIDOMWindow> domWindow = do_QueryInterface(window);
michael@0 433 if (domWindow) {
michael@0 434 bool closed = false;
michael@0 435 domWindow->GetClosed(&closed);
michael@0 436 if (!closed) {
michael@0 437 rv = NS_ERROR_FAILURE;
michael@0 438 break;
michael@0 439 }
michael@0 440 }
michael@0 441 }
michael@0 442 }
michael@0 443 }
michael@0 444 }
michael@0 445 }
michael@0 446
michael@0 447 if (ferocity == eForceQuit) {
michael@0 448 // do it!
michael@0 449
michael@0 450 // No chance of the shutdown being cancelled from here on; tell people
michael@0 451 // we're shutting down for sure while all services are still available.
michael@0 452 if (obsService) {
michael@0 453 NS_NAMED_LITERAL_STRING(shutdownStr, "shutdown");
michael@0 454 NS_NAMED_LITERAL_STRING(restartStr, "restart");
michael@0 455 obsService->NotifyObservers(nullptr, "quit-application",
michael@0 456 (mRestart || mRestartTouchEnvironment) ?
michael@0 457 restartStr.get() : shutdownStr.get());
michael@0 458 }
michael@0 459
michael@0 460 if (!mRunning) {
michael@0 461 postedExitEvent = true;
michael@0 462 }
michael@0 463 else {
michael@0 464 // no matter what, make sure we send the exit event. If
michael@0 465 // worst comes to worst, we'll do a leaky shutdown but we WILL
michael@0 466 // shut down. Well, assuming that all *this* stuff works ;-).
michael@0 467 nsCOMPtr<nsIRunnable> event = new nsAppExitEvent(this);
michael@0 468 rv = NS_DispatchToCurrentThread(event);
michael@0 469 if (NS_SUCCEEDED(rv)) {
michael@0 470 postedExitEvent = true;
michael@0 471 }
michael@0 472 else {
michael@0 473 NS_WARNING("failed to dispatch nsAppExitEvent");
michael@0 474 }
michael@0 475 }
michael@0 476 }
michael@0 477
michael@0 478 // turn off the reentrancy check flag, but not if we have
michael@0 479 // more asynchronous work to do still.
michael@0 480 if (!postedExitEvent)
michael@0 481 mShuttingDown = false;
michael@0 482 return rv;
michael@0 483 }
michael@0 484
michael@0 485
michael@0 486 void
michael@0 487 nsAppStartup::CloseAllWindows()
michael@0 488 {
michael@0 489 nsCOMPtr<nsIWindowMediator> mediator
michael@0 490 (do_GetService(NS_WINDOWMEDIATOR_CONTRACTID));
michael@0 491
michael@0 492 nsCOMPtr<nsISimpleEnumerator> windowEnumerator;
michael@0 493
michael@0 494 mediator->GetEnumerator(nullptr, getter_AddRefs(windowEnumerator));
michael@0 495
michael@0 496 if (!windowEnumerator)
michael@0 497 return;
michael@0 498
michael@0 499 bool more;
michael@0 500 while (NS_SUCCEEDED(windowEnumerator->HasMoreElements(&more)) && more) {
michael@0 501 nsCOMPtr<nsISupports> isupports;
michael@0 502 if (NS_FAILED(windowEnumerator->GetNext(getter_AddRefs(isupports))))
michael@0 503 break;
michael@0 504
michael@0 505 nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(isupports);
michael@0 506 NS_ASSERTION(window, "not an nsPIDOMWindow");
michael@0 507 if (window)
michael@0 508 window->ForceClose();
michael@0 509 }
michael@0 510 }
michael@0 511
michael@0 512 NS_IMETHODIMP
michael@0 513 nsAppStartup::EnterLastWindowClosingSurvivalArea(void)
michael@0 514 {
michael@0 515 ++mConsiderQuitStopper;
michael@0 516 return NS_OK;
michael@0 517 }
michael@0 518
michael@0 519
michael@0 520 NS_IMETHODIMP
michael@0 521 nsAppStartup::ExitLastWindowClosingSurvivalArea(void)
michael@0 522 {
michael@0 523 NS_ASSERTION(mConsiderQuitStopper > 0, "consider quit stopper out of bounds");
michael@0 524 --mConsiderQuitStopper;
michael@0 525
michael@0 526 if (mRunning)
michael@0 527 Quit(eConsiderQuit);
michael@0 528
michael@0 529 return NS_OK;
michael@0 530 }
michael@0 531
michael@0 532 //
michael@0 533 // nsAppStartup->nsIAppStartup2
michael@0 534 //
michael@0 535
michael@0 536 NS_IMETHODIMP
michael@0 537 nsAppStartup::GetShuttingDown(bool *aResult)
michael@0 538 {
michael@0 539 *aResult = mShuttingDown;
michael@0 540 return NS_OK;
michael@0 541 }
michael@0 542
michael@0 543 NS_IMETHODIMP
michael@0 544 nsAppStartup::GetStartingUp(bool *aResult)
michael@0 545 {
michael@0 546 *aResult = mStartingUp;
michael@0 547 return NS_OK;
michael@0 548 }
michael@0 549
michael@0 550 NS_IMETHODIMP
michael@0 551 nsAppStartup::DoneStartingUp()
michael@0 552 {
michael@0 553 // This must be called once at most
michael@0 554 MOZ_ASSERT(mStartingUp);
michael@0 555
michael@0 556 mStartingUp = false;
michael@0 557 return NS_OK;
michael@0 558 }
michael@0 559
michael@0 560 NS_IMETHODIMP
michael@0 561 nsAppStartup::GetRestarting(bool *aResult)
michael@0 562 {
michael@0 563 *aResult = mRestart;
michael@0 564 return NS_OK;
michael@0 565 }
michael@0 566
michael@0 567 NS_IMETHODIMP
michael@0 568 nsAppStartup::GetWasRestarted(bool *aResult)
michael@0 569 {
michael@0 570 char *mozAppRestart = PR_GetEnv("MOZ_APP_RESTART");
michael@0 571
michael@0 572 /* When calling PR_SetEnv() with an empty value the existing variable may
michael@0 573 * be unset or set to the empty string depending on the underlying platform
michael@0 574 * thus we have to check if the variable is present and not empty. */
michael@0 575 *aResult = mozAppRestart && (strcmp(mozAppRestart, "") != 0);
michael@0 576
michael@0 577 return NS_OK;
michael@0 578 }
michael@0 579
michael@0 580 NS_IMETHODIMP
michael@0 581 nsAppStartup::GetRestartingTouchEnvironment(bool *aResult)
michael@0 582 {
michael@0 583 NS_ENSURE_ARG_POINTER(aResult);
michael@0 584 *aResult = mRestartTouchEnvironment;
michael@0 585 return NS_OK;
michael@0 586 }
michael@0 587
michael@0 588 NS_IMETHODIMP
michael@0 589 nsAppStartup::SetInterrupted(bool aInterrupted)
michael@0 590 {
michael@0 591 mInterrupted = aInterrupted;
michael@0 592 return NS_OK;
michael@0 593 }
michael@0 594
michael@0 595 NS_IMETHODIMP
michael@0 596 nsAppStartup::GetInterrupted(bool *aInterrupted)
michael@0 597 {
michael@0 598 *aInterrupted = mInterrupted;
michael@0 599 return NS_OK;
michael@0 600 }
michael@0 601
michael@0 602 //
michael@0 603 // nsAppStartup->nsIWindowCreator
michael@0 604 //
michael@0 605
michael@0 606 NS_IMETHODIMP
michael@0 607 nsAppStartup::CreateChromeWindow(nsIWebBrowserChrome *aParent,
michael@0 608 uint32_t aChromeFlags,
michael@0 609 nsIWebBrowserChrome **_retval)
michael@0 610 {
michael@0 611 bool cancel;
michael@0 612 return CreateChromeWindow2(aParent, aChromeFlags, 0, 0, &cancel, _retval);
michael@0 613 }
michael@0 614
michael@0 615
michael@0 616 //
michael@0 617 // nsAppStartup->nsIWindowCreator2
michael@0 618 //
michael@0 619
michael@0 620 NS_IMETHODIMP
michael@0 621 nsAppStartup::CreateChromeWindow2(nsIWebBrowserChrome *aParent,
michael@0 622 uint32_t aChromeFlags,
michael@0 623 uint32_t aContextFlags,
michael@0 624 nsIURI *aURI,
michael@0 625 bool *aCancel,
michael@0 626 nsIWebBrowserChrome **_retval)
michael@0 627 {
michael@0 628 NS_ENSURE_ARG_POINTER(aCancel);
michael@0 629 NS_ENSURE_ARG_POINTER(_retval);
michael@0 630 *aCancel = false;
michael@0 631 *_retval = 0;
michael@0 632
michael@0 633 // Non-modal windows cannot be opened if we are attempting to quit
michael@0 634 if (mAttemptingQuit && (aChromeFlags & nsIWebBrowserChrome::CHROME_MODAL) == 0)
michael@0 635 return NS_ERROR_ILLEGAL_DURING_SHUTDOWN;
michael@0 636
michael@0 637 nsCOMPtr<nsIXULWindow> newWindow;
michael@0 638
michael@0 639 if (aParent) {
michael@0 640 nsCOMPtr<nsIXULWindow> xulParent(do_GetInterface(aParent));
michael@0 641 NS_ASSERTION(xulParent, "window created using non-XUL parent. that's unexpected, but may work.");
michael@0 642
michael@0 643 if (xulParent)
michael@0 644 xulParent->CreateNewWindow(aChromeFlags, getter_AddRefs(newWindow));
michael@0 645 // And if it fails, don't try again without a parent. It could fail
michael@0 646 // intentionally (bug 115969).
michael@0 647 } else { // try using basic methods:
michael@0 648 /* You really shouldn't be making dependent windows without a parent.
michael@0 649 But unparented modal (and therefore dependent) windows happen
michael@0 650 in our codebase, so we allow it after some bellyaching: */
michael@0 651 if (aChromeFlags & nsIWebBrowserChrome::CHROME_DEPENDENT)
michael@0 652 NS_WARNING("dependent window created without a parent");
michael@0 653
michael@0 654 nsCOMPtr<nsIAppShellService> appShell(do_GetService(NS_APPSHELLSERVICE_CONTRACTID));
michael@0 655 if (!appShell)
michael@0 656 return NS_ERROR_FAILURE;
michael@0 657
michael@0 658 appShell->CreateTopLevelWindow(0, 0, aChromeFlags,
michael@0 659 nsIAppShellService::SIZE_TO_CONTENT,
michael@0 660 nsIAppShellService::SIZE_TO_CONTENT,
michael@0 661 getter_AddRefs(newWindow));
michael@0 662 }
michael@0 663
michael@0 664 // if anybody gave us anything to work with, use it
michael@0 665 if (newWindow) {
michael@0 666 newWindow->SetContextFlags(aContextFlags);
michael@0 667 nsCOMPtr<nsIInterfaceRequestor> thing(do_QueryInterface(newWindow));
michael@0 668 if (thing)
michael@0 669 CallGetInterface(thing.get(), _retval);
michael@0 670 }
michael@0 671
michael@0 672 return *_retval ? NS_OK : NS_ERROR_FAILURE;
michael@0 673 }
michael@0 674
michael@0 675
michael@0 676 //
michael@0 677 // nsAppStartup->nsIObserver
michael@0 678 //
michael@0 679
michael@0 680 NS_IMETHODIMP
michael@0 681 nsAppStartup::Observe(nsISupports *aSubject,
michael@0 682 const char *aTopic, const char16_t *aData)
michael@0 683 {
michael@0 684 NS_ASSERTION(mAppShell, "appshell service notified before appshell built");
michael@0 685 if (!strcmp(aTopic, "quit-application-forced")) {
michael@0 686 mShuttingDown = true;
michael@0 687 }
michael@0 688 else if (!strcmp(aTopic, "profile-change-teardown")) {
michael@0 689 if (!mShuttingDown) {
michael@0 690 EnterLastWindowClosingSurvivalArea();
michael@0 691 CloseAllWindows();
michael@0 692 ExitLastWindowClosingSurvivalArea();
michael@0 693 }
michael@0 694 } else if (!strcmp(aTopic, "xul-window-registered")) {
michael@0 695 EnterLastWindowClosingSurvivalArea();
michael@0 696 } else if (!strcmp(aTopic, "xul-window-destroyed")) {
michael@0 697 ExitLastWindowClosingSurvivalArea();
michael@0 698 } else if (!strcmp(aTopic, "sessionstore-windows-restored")) {
michael@0 699 StartupTimeline::Record(StartupTimeline::SESSION_RESTORED);
michael@0 700 IOInterposer::EnteringNextStage();
michael@0 701 #if defined(XP_WIN)
michael@0 702 if (mSessionWindowRestoredProbe) {
michael@0 703 mSessionWindowRestoredProbe->Trigger();
michael@0 704 }
michael@0 705 } else if (!strcmp(aTopic, "places-init-complete")) {
michael@0 706 if (mPlacesInitCompleteProbe) {
michael@0 707 mPlacesInitCompleteProbe->Trigger();
michael@0 708 }
michael@0 709 #endif //defined(XP_WIN)
michael@0 710 } else if (!strcmp(aTopic, "sessionstore-init-started")) {
michael@0 711 StartupTimeline::Record(StartupTimeline::SESSION_RESTORE_INIT);
michael@0 712 } else if (!strcmp(aTopic, "xpcom-shutdown")) {
michael@0 713 IOInterposer::EnteringNextStage();
michael@0 714 #if defined(XP_WIN)
michael@0 715 if (mXPCOMShutdownProbe) {
michael@0 716 mXPCOMShutdownProbe->Trigger();
michael@0 717 }
michael@0 718 #endif // defined(XP_WIN)
michael@0 719 } else {
michael@0 720 NS_ERROR("Unexpected observer topic.");
michael@0 721 }
michael@0 722
michael@0 723 return NS_OK;
michael@0 724 }
michael@0 725
michael@0 726 NS_IMETHODIMP
michael@0 727 nsAppStartup::GetStartupInfo(JSContext* aCx, JS::MutableHandle<JS::Value> aRetval)
michael@0 728 {
michael@0 729 JS::Rooted<JSObject*> obj(aCx, JS_NewObject(aCx, nullptr, JS::NullPtr(), JS::NullPtr()));
michael@0 730
michael@0 731 aRetval.setObject(*obj);
michael@0 732
michael@0 733 TimeStamp procTime = StartupTimeline::Get(StartupTimeline::PROCESS_CREATION);
michael@0 734 TimeStamp now = TimeStamp::Now();
michael@0 735 PRTime absNow = PR_Now();
michael@0 736
michael@0 737 if (procTime.IsNull()) {
michael@0 738 bool error = false;
michael@0 739
michael@0 740 procTime = TimeStamp::ProcessCreation(error);
michael@0 741
michael@0 742 if (error) {
michael@0 743 Telemetry::Accumulate(Telemetry::STARTUP_MEASUREMENT_ERRORS,
michael@0 744 StartupTimeline::PROCESS_CREATION);
michael@0 745 }
michael@0 746
michael@0 747 StartupTimeline::Record(StartupTimeline::PROCESS_CREATION, procTime);
michael@0 748 }
michael@0 749
michael@0 750 for (int i = StartupTimeline::PROCESS_CREATION;
michael@0 751 i < StartupTimeline::MAX_EVENT_ID;
michael@0 752 ++i)
michael@0 753 {
michael@0 754 StartupTimeline::Event ev = static_cast<StartupTimeline::Event>(i);
michael@0 755 TimeStamp stamp = StartupTimeline::Get(ev);
michael@0 756
michael@0 757 if (stamp.IsNull() && (ev == StartupTimeline::MAIN)) {
michael@0 758 // Always define main to aid with bug 689256.
michael@0 759 stamp = procTime;
michael@0 760 MOZ_ASSERT(!stamp.IsNull());
michael@0 761 Telemetry::Accumulate(Telemetry::STARTUP_MEASUREMENT_ERRORS,
michael@0 762 StartupTimeline::MAIN);
michael@0 763 }
michael@0 764
michael@0 765 if (!stamp.IsNull()) {
michael@0 766 if (stamp >= procTime) {
michael@0 767 PRTime prStamp = ComputeAbsoluteTimestamp(absNow, now, stamp)
michael@0 768 / PR_USEC_PER_MSEC;
michael@0 769 JS::Rooted<JSObject*> date(aCx, JS_NewDateObjectMsec(aCx, prStamp));
michael@0 770 JS_DefineProperty(aCx, obj, StartupTimeline::Describe(ev), date, JSPROP_ENUMERATE);
michael@0 771 } else {
michael@0 772 Telemetry::Accumulate(Telemetry::STARTUP_MEASUREMENT_ERRORS, ev);
michael@0 773 }
michael@0 774 }
michael@0 775 }
michael@0 776
michael@0 777 return NS_OK;
michael@0 778 }
michael@0 779
michael@0 780 NS_IMETHODIMP
michael@0 781 nsAppStartup::GetAutomaticSafeModeNecessary(bool *_retval)
michael@0 782 {
michael@0 783 NS_ENSURE_ARG_POINTER(_retval);
michael@0 784
michael@0 785 bool alwaysSafe = false;
michael@0 786 Preferences::GetBool(kPrefAlwaysUseSafeMode, &alwaysSafe);
michael@0 787
michael@0 788 if (!alwaysSafe) {
michael@0 789 #if DEBUG
michael@0 790 mIsSafeModeNecessary = false;
michael@0 791 #else
michael@0 792 mIsSafeModeNecessary &= !PR_GetEnv("MOZ_DISABLE_AUTO_SAFE_MODE");
michael@0 793 #endif
michael@0 794 }
michael@0 795
michael@0 796 *_retval = mIsSafeModeNecessary;
michael@0 797 return NS_OK;
michael@0 798 }
michael@0 799
michael@0 800 NS_IMETHODIMP
michael@0 801 nsAppStartup::TrackStartupCrashBegin(bool *aIsSafeModeNecessary)
michael@0 802 {
michael@0 803 const int32_t MAX_TIME_SINCE_STARTUP = 6 * 60 * 60 * 1000;
michael@0 804 const int32_t MAX_STARTUP_BUFFER = 10;
michael@0 805 nsresult rv;
michael@0 806
michael@0 807 mStartupCrashTrackingEnded = false;
michael@0 808
michael@0 809 StartupTimeline::Record(StartupTimeline::STARTUP_CRASH_DETECTION_BEGIN);
michael@0 810
michael@0 811 bool hasLastSuccess = Preferences::HasUserValue(kPrefLastSuccess);
michael@0 812 if (!hasLastSuccess) {
michael@0 813 // Clear so we don't get stuck with SafeModeNecessary returning true if we
michael@0 814 // have had too many recent crashes and the last success pref is missing.
michael@0 815 Preferences::ClearUser(kPrefRecentCrashes);
michael@0 816 return NS_ERROR_NOT_AVAILABLE;
michael@0 817 }
michael@0 818
michael@0 819 bool inSafeMode = false;
michael@0 820 nsCOMPtr<nsIXULRuntime> xr = do_GetService(XULRUNTIME_SERVICE_CONTRACTID);
michael@0 821 NS_ENSURE_TRUE(xr, NS_ERROR_FAILURE);
michael@0 822
michael@0 823 xr->GetInSafeMode(&inSafeMode);
michael@0 824
michael@0 825 PRTime replacedLockTime;
michael@0 826 rv = xr->GetReplacedLockTime(&replacedLockTime);
michael@0 827
michael@0 828 if (NS_FAILED(rv) || !replacedLockTime) {
michael@0 829 if (!inSafeMode)
michael@0 830 Preferences::ClearUser(kPrefRecentCrashes);
michael@0 831 GetAutomaticSafeModeNecessary(aIsSafeModeNecessary);
michael@0 832 return NS_OK;
michael@0 833 }
michael@0 834
michael@0 835 // check whether safe mode is necessary
michael@0 836 int32_t maxResumedCrashes = -1;
michael@0 837 rv = Preferences::GetInt(kPrefMaxResumedCrashes, &maxResumedCrashes);
michael@0 838 NS_ENSURE_SUCCESS(rv, NS_OK);
michael@0 839
michael@0 840 int32_t recentCrashes = 0;
michael@0 841 Preferences::GetInt(kPrefRecentCrashes, &recentCrashes);
michael@0 842 mIsSafeModeNecessary = (recentCrashes > maxResumedCrashes && maxResumedCrashes != -1);
michael@0 843
michael@0 844 // Bug 731613 - Don't check if the last startup was a crash if XRE_PROFILE_PATH is set. After
michael@0 845 // profile manager, the profile lock's mod. time has been changed so can't be used on this startup.
michael@0 846 // After a restart, it's safe to assume the last startup was successful.
michael@0 847 char *xreProfilePath = PR_GetEnv("XRE_PROFILE_PATH");
michael@0 848 if (xreProfilePath) {
michael@0 849 GetAutomaticSafeModeNecessary(aIsSafeModeNecessary);
michael@0 850 return NS_ERROR_NOT_AVAILABLE;
michael@0 851 }
michael@0 852
michael@0 853 // time of last successful startup
michael@0 854 int32_t lastSuccessfulStartup;
michael@0 855 rv = Preferences::GetInt(kPrefLastSuccess, &lastSuccessfulStartup);
michael@0 856 NS_ENSURE_SUCCESS(rv, rv);
michael@0 857
michael@0 858 int32_t lockSeconds = (int32_t)(replacedLockTime / PR_MSEC_PER_SEC);
michael@0 859
michael@0 860 // started close enough to good startup so call it good
michael@0 861 if (lockSeconds <= lastSuccessfulStartup + MAX_STARTUP_BUFFER
michael@0 862 && lockSeconds >= lastSuccessfulStartup - MAX_STARTUP_BUFFER) {
michael@0 863 GetAutomaticSafeModeNecessary(aIsSafeModeNecessary);
michael@0 864 return NS_OK;
michael@0 865 }
michael@0 866
michael@0 867 // sanity check that the pref set at last success is not greater than the current time
michael@0 868 if (PR_Now() / PR_USEC_PER_SEC <= lastSuccessfulStartup)
michael@0 869 return NS_ERROR_FAILURE;
michael@0 870
michael@0 871 // The last startup was a crash so include it in the count regardless of when it happened.
michael@0 872 Telemetry::Accumulate(Telemetry::STARTUP_CRASH_DETECTED, true);
michael@0 873
michael@0 874 if (inSafeMode) {
michael@0 875 GetAutomaticSafeModeNecessary(aIsSafeModeNecessary);
michael@0 876 return NS_OK;
michael@0 877 }
michael@0 878
michael@0 879 PRTime now = (PR_Now() / PR_USEC_PER_MSEC);
michael@0 880 // if the last startup attempt which crashed was in the last 6 hours
michael@0 881 if (replacedLockTime >= now - MAX_TIME_SINCE_STARTUP) {
michael@0 882 NS_WARNING("Last startup was detected as a crash.");
michael@0 883 recentCrashes++;
michael@0 884 rv = Preferences::SetInt(kPrefRecentCrashes, recentCrashes);
michael@0 885 } else {
michael@0 886 // Otherwise ignore that crash and all previous since it may not be applicable anymore
michael@0 887 // and we don't want someone to get stuck in safe mode if their prefs are read-only.
michael@0 888 rv = Preferences::ClearUser(kPrefRecentCrashes);
michael@0 889 }
michael@0 890 NS_ENSURE_SUCCESS(rv, rv);
michael@0 891
michael@0 892 // recalculate since recent crashes count may have changed above
michael@0 893 mIsSafeModeNecessary = (recentCrashes > maxResumedCrashes && maxResumedCrashes != -1);
michael@0 894
michael@0 895 nsCOMPtr<nsIPrefService> prefs = Preferences::GetService();
michael@0 896 rv = prefs->SavePrefFile(nullptr); // flush prefs to disk since we are tracking crashes
michael@0 897 NS_ENSURE_SUCCESS(rv, rv);
michael@0 898
michael@0 899 GetAutomaticSafeModeNecessary(aIsSafeModeNecessary);
michael@0 900 return rv;
michael@0 901 }
michael@0 902
michael@0 903 NS_IMETHODIMP
michael@0 904 nsAppStartup::TrackStartupCrashEnd()
michael@0 905 {
michael@0 906 bool inSafeMode = false;
michael@0 907 nsCOMPtr<nsIXULRuntime> xr = do_GetService(XULRUNTIME_SERVICE_CONTRACTID);
michael@0 908 if (xr)
michael@0 909 xr->GetInSafeMode(&inSafeMode);
michael@0 910
michael@0 911 // return if we already ended or we're restarting into safe mode
michael@0 912 if (mStartupCrashTrackingEnded || (mIsSafeModeNecessary && !inSafeMode))
michael@0 913 return NS_OK;
michael@0 914 mStartupCrashTrackingEnded = true;
michael@0 915
michael@0 916 StartupTimeline::Record(StartupTimeline::STARTUP_CRASH_DETECTION_END);
michael@0 917
michael@0 918 // Use the timestamp of XRE_main as an approximation for the lock file timestamp.
michael@0 919 // See MAX_STARTUP_BUFFER for the buffer time period.
michael@0 920 TimeStamp mainTime = StartupTimeline::Get(StartupTimeline::MAIN);
michael@0 921 TimeStamp now = TimeStamp::Now();
michael@0 922 PRTime prNow = PR_Now();
michael@0 923 nsresult rv;
michael@0 924
michael@0 925 if (mainTime.IsNull()) {
michael@0 926 NS_WARNING("Could not get StartupTimeline::MAIN time.");
michael@0 927 } else {
michael@0 928 uint64_t lockFileTime = ComputeAbsoluteTimestamp(prNow, now, mainTime);
michael@0 929
michael@0 930 rv = Preferences::SetInt(kPrefLastSuccess,
michael@0 931 (int32_t)(lockFileTime / PR_USEC_PER_SEC));
michael@0 932
michael@0 933 if (NS_FAILED(rv))
michael@0 934 NS_WARNING("Could not set startup crash detection pref.");
michael@0 935 }
michael@0 936
michael@0 937 if (inSafeMode && mIsSafeModeNecessary) {
michael@0 938 // On a successful startup in automatic safe mode, allow the user one more crash
michael@0 939 // in regular mode before returning to safe mode.
michael@0 940 int32_t maxResumedCrashes = 0;
michael@0 941 int32_t prefType;
michael@0 942 rv = Preferences::GetDefaultRootBranch()->GetPrefType(kPrefMaxResumedCrashes, &prefType);
michael@0 943 NS_ENSURE_SUCCESS(rv, rv);
michael@0 944 if (prefType == nsIPrefBranch::PREF_INT) {
michael@0 945 rv = Preferences::GetInt(kPrefMaxResumedCrashes, &maxResumedCrashes);
michael@0 946 NS_ENSURE_SUCCESS(rv, rv);
michael@0 947 }
michael@0 948 rv = Preferences::SetInt(kPrefRecentCrashes, maxResumedCrashes);
michael@0 949 NS_ENSURE_SUCCESS(rv, rv);
michael@0 950 } else if (!inSafeMode) {
michael@0 951 // clear the count of recent crashes after a succesful startup when not in safe mode
michael@0 952 rv = Preferences::ClearUser(kPrefRecentCrashes);
michael@0 953 if (NS_FAILED(rv)) NS_WARNING("Could not clear startup crash count.");
michael@0 954 }
michael@0 955 nsCOMPtr<nsIPrefService> prefs = Preferences::GetService();
michael@0 956 rv = prefs->SavePrefFile(nullptr); // flush prefs to disk since we are tracking crashes
michael@0 957
michael@0 958 return rv;
michael@0 959 }
michael@0 960
michael@0 961 NS_IMETHODIMP
michael@0 962 nsAppStartup::RestartInSafeMode(uint32_t aQuitMode)
michael@0 963 {
michael@0 964 PR_SetEnv("MOZ_SAFE_MODE_RESTART=1");
michael@0 965 this->Quit(aQuitMode | nsIAppStartup::eRestart);
michael@0 966
michael@0 967 return NS_OK;
michael@0 968 }

mercurial