Bug 1865172 Part 1 - Always store a page name value when a breakpoint is first found...
[gecko.git] / toolkit / xre / nsAppRunner.cpp
blob230d0da3e75fe9eb820854c8ab7464da0488cb26
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "mozilla/dom/ContentParent.h"
7 #include "mozilla/dom/ContentChild.h"
8 #include "mozilla/ipc/GeckoChildProcessHost.h"
10 #include "mozilla/AppShutdown.h"
11 #include "mozilla/ArrayUtils.h"
12 #include "mozilla/Assertions.h"
13 #include "mozilla/Attributes.h"
14 #include "mozilla/Components.h"
15 #include "mozilla/FilePreferences.h"
16 #include "mozilla/ChaosMode.h"
17 #include "mozilla/CmdLineAndEnvUtils.h"
18 #include "mozilla/IOInterposer.h"
19 #include "mozilla/ipc/UtilityProcessChild.h"
20 #include "mozilla/Likely.h"
21 #include "mozilla/MemoryChecking.h"
22 #include "mozilla/Poison.h"
23 #include "mozilla/Preferences.h"
24 #include "mozilla/PreferenceSheet.h"
25 #include "mozilla/Printf.h"
26 #include "mozilla/ProcessType.h"
27 #include "mozilla/ResultExtensions.h"
28 #include "mozilla/RuntimeExceptionModule.h"
29 #include "mozilla/ScopeExit.h"
30 #include "mozilla/StaticPrefs_browser.h"
31 #include "mozilla/StaticPrefs_fission.h"
32 #include "mozilla/StaticPrefs_webgl.h"
33 #include "mozilla/StaticPrefs_widget.h"
34 #include "mozilla/Telemetry.h"
35 #include "mozilla/Utf8.h"
36 #include "mozilla/intl/LocaleService.h"
37 #include "mozilla/JSONWriter.h"
38 #include "mozilla/gfx/gfxVars.h"
39 #include "mozilla/glean/GleanMetrics.h"
40 #include "mozilla/glean/GleanPings.h"
41 #include "mozilla/widget/TextRecognition.h"
42 #include "BaseProfiler.h"
44 #include "nsAppRunner.h"
45 #include "mozilla/XREAppData.h"
46 #include "mozilla/Bootstrap.h"
47 #if defined(MOZ_UPDATER) && !defined(MOZ_WIDGET_ANDROID)
48 # include "nsUpdateDriver.h"
49 # include "nsUpdateSyncManager.h"
50 #endif
51 #include "ProfileReset.h"
53 #ifdef MOZ_INSTRUMENT_EVENT_LOOP
54 # include "EventTracer.h"
55 #endif
57 #ifdef XP_MACOSX
58 # include "nsVersionComparator.h"
59 # include "MacLaunchHelper.h"
60 # include "MacApplicationDelegate.h"
61 # include "MacAutoreleasePool.h"
62 # include "MacRunFromDmgUtils.h"
63 // these are needed for sysctl
64 # include <sys/types.h>
65 # include <sys/sysctl.h>
66 #endif
68 #include "prnetdb.h"
69 #include "prprf.h"
70 #include "prproces.h"
71 #include "prenv.h"
72 #include "prtime.h"
74 #include "nsIAppStartup.h"
75 #include "nsCategoryManagerUtils.h"
76 #include "nsIMutableArray.h"
77 #include "nsCommandLine.h"
78 #include "nsIComponentRegistrar.h"
79 #include "nsIDialogParamBlock.h"
80 #include "mozilla/ModuleUtils.h"
81 #include "nsIIOService.h"
82 #include "nsIObserverService.h"
83 #include "nsINativeAppSupport.h"
84 #include "nsIPlatformInfo.h"
85 #include "nsIProcess.h"
86 #include "nsIProfileUnlocker.h"
87 #include "nsIPromptService.h"
88 #include "nsIPropertyBag2.h"
89 #include "nsIServiceManager.h"
90 #include "nsIStringBundle.h"
91 #include "nsISupportsPrimitives.h"
92 #include "nsIToolkitProfile.h"
93 #include "nsToolkitProfileService.h"
94 #include "nsIURI.h"
95 #include "nsIURL.h"
96 #include "nsIWindowCreator.h"
97 #include "nsIWindowWatcher.h"
98 #include "nsIXULAppInfo.h"
99 #include "nsIXULRuntime.h"
100 #include "nsPIDOMWindow.h"
101 #include "nsIWidget.h"
102 #include "nsAppShellCID.h"
103 #include "mozilla/dom/quota/QuotaManager.h"
104 #include "mozilla/scache/StartupCache.h"
105 #include "gfxPlatform.h"
106 #include "PDMFactory.h"
107 #ifdef XP_MACOSX
108 # include "gfxPlatformMac.h"
109 #endif
111 #include "mozilla/Unused.h"
113 #ifdef XP_WIN
114 # include "nsIWinAppHelper.h"
115 # include <windows.h>
116 # include <intrin.h>
117 # include <math.h>
118 # include "cairo/cairo-features.h"
119 # include "detect_win32k_conflicts.h"
120 # include "mozilla/PreXULSkeletonUI.h"
121 # include "mozilla/DllPrefetchExperimentRegistryInfo.h"
122 # include "mozilla/WindowsBCryptInitialization.h"
123 # include "mozilla/WindowsDllBlocklist.h"
124 # include "mozilla/WindowsMsctfInitialization.h"
125 # include "mozilla/WindowsProcessMitigations.h"
126 # include "mozilla/WindowsVersion.h"
127 # include "mozilla/WinHeaderOnlyUtils.h"
128 # include "mozilla/mscom/ProcessRuntime.h"
129 # include "mozilla/mscom/ProfilerMarkers.h"
130 # include "WinTokenUtils.h"
132 # if defined(MOZ_LAUNCHER_PROCESS)
133 # include "mozilla/LauncherRegistryInfo.h"
134 # endif
136 # if defined(MOZ_DEFAULT_BROWSER_AGENT)
137 # include "nsIWindowsRegKey.h"
138 # endif
140 # ifndef PROCESS_DEP_ENABLE
141 # define PROCESS_DEP_ENABLE 0x1
142 # endif
143 #endif
145 #if defined(MOZ_SANDBOX)
146 # include "mozilla/SandboxSettings.h"
147 #endif
149 #ifdef ACCESSIBILITY
150 # include "nsAccessibilityService.h"
151 # if defined(XP_WIN)
152 # include "mozilla/a11y/Compatibility.h"
153 # include "mozilla/a11y/Platform.h"
154 # endif
155 #endif
157 #include "nsCRT.h"
158 #include "nsCOMPtr.h"
159 #include "nsDirectoryServiceDefs.h"
160 #include "nsDirectoryServiceUtils.h"
161 #include "nsEmbedCID.h"
162 #include "nsIDUtils.h"
163 #include "nsNetUtil.h"
164 #include "nsReadableUtils.h"
165 #include "nsXPCOM.h"
166 #include "nsXPCOMCIDInternal.h"
167 #include "nsString.h"
168 #include "nsPrintfCString.h"
169 #include "nsVersionComparator.h"
171 #include "nsAppDirectoryServiceDefs.h"
172 #include "nsXULAppAPI.h"
173 #include "nsXREDirProvider.h"
175 #include "nsINIParser.h"
176 #include "mozilla/Omnijar.h"
177 #include "mozilla/StartupTimeline.h"
178 #include "mozilla/LateWriteChecks.h"
180 #include <stdlib.h>
181 #include <locale.h>
183 #ifdef XP_UNIX
184 # include <errno.h>
185 # include <pwd.h>
186 # include <string.h>
187 # include <sys/resource.h>
188 # include <sys/stat.h>
189 # include <unistd.h>
190 #endif
192 #ifdef XP_WIN
193 # include <process.h>
194 # include <shlobj.h>
195 # include "mozilla/WinDllServices.h"
196 # include "nsThreadUtils.h"
197 # include "WinUtils.h"
198 #endif
200 #ifdef XP_MACOSX
201 # include "nsILocalFileMac.h"
202 # include "nsCommandLineServiceMac.h"
203 #endif
205 // for X remote support
206 #if defined(MOZ_HAS_REMOTE)
207 # include "nsRemoteService.h"
208 #endif
210 #if defined(DEBUG) && defined(XP_WIN)
211 # include <malloc.h>
212 #endif
214 #if defined(XP_MACOSX)
215 # include <Carbon/Carbon.h>
216 #endif
218 #ifdef DEBUG
219 # include "mozilla/Logging.h"
220 #endif
222 #ifdef MOZ_JPROF
223 # include "jprof.h"
224 #endif
226 #include "nsExceptionHandler.h"
227 #include "nsICrashReporter.h"
228 #include "nsIPrefService.h"
229 #include "nsIMemoryInfoDumper.h"
230 #if defined(XP_LINUX) && !defined(ANDROID)
231 # include "mozilla/widget/LSBUtils.h"
232 #endif
234 #include "base/command_line.h"
235 #include "GTestRunner.h"
237 #ifdef MOZ_WIDGET_ANDROID
238 # include "mozilla/java/GeckoAppShellWrappers.h"
239 #endif
241 #if defined(MOZ_SANDBOX)
242 # if defined(XP_LINUX) && !defined(ANDROID)
243 # include "mozilla/SandboxInfo.h"
244 # elif defined(XP_WIN)
245 # include "sandboxBroker.h"
246 # endif
247 #endif
249 #ifdef MOZ_CODE_COVERAGE
250 # include "mozilla/CodeCoverageHandler.h"
251 #endif
253 #include "GMPProcessChild.h"
254 #include "SafeMode.h"
256 #ifdef MOZ_BACKGROUNDTASKS
257 # include "mozilla/BackgroundTasks.h"
258 # include "nsIPowerManagerService.h"
259 # include "nsIStringBundle.h"
260 #endif
262 #ifdef USE_GLX_TEST
263 # include "mozilla/GUniquePtr.h"
264 # include "mozilla/GfxInfo.h"
265 #endif
267 #ifdef MOZ_WIDGET_GTK
268 # include "nsAppShell.h"
269 #endif
271 extern uint32_t gRestartMode;
272 extern void InstallSignalHandlers(const char* ProgramName);
274 #define FILE_COMPATIBILITY_INFO "compatibility.ini"_ns
275 #define FILE_INVALIDATE_CACHES ".purgecaches"_ns
276 #define FILE_STARTUP_INCOMPLETE u".startup-incomplete"_ns
278 #if defined(MOZ_BLOCK_PROFILE_DOWNGRADE) || defined(MOZ_LAUNCHER_PROCESS) || \
279 defined(MOZ_DEFAULT_BROWSER_AGENT)
280 static const char kPrefHealthReportUploadEnabled[] =
281 "datareporting.healthreport.uploadEnabled";
282 #endif // defined(MOZ_BLOCK_PROFILE_DOWNGRADE) || defined(MOZ_LAUNCHER_PROCESS)
283 // || defined(MOZ_DEFAULT_BROWSER_AGENT)
284 #if defined(MOZ_DEFAULT_BROWSER_AGENT)
285 static const char kPrefDefaultAgentEnabled[] = "default-browser-agent.enabled";
287 static const char kPrefServicesSettingsServer[] = "services.settings.server";
288 static const char kPrefSecurityContentSignatureRootHash[] =
289 "security.content.signature.root_hash";
290 static const char kPrefSetDefaultBrowserUserChoicePref[] =
291 "browser.shell.setDefaultBrowserUserChoice";
292 #endif // defined(MOZ_DEFAULT_BROWSER_AGENT)
294 #if defined(XP_WIN)
295 static const char kPrefThemeId[] = "extensions.activeThemeID";
296 static const char kPrefBrowserStartupBlankWindow[] =
297 "browser.startup.blankWindow";
298 static const char kPrefPreXulSkeletonUI[] = "browser.startup.preXulSkeletonUI";
299 #endif // defined(XP_WIN)
301 #if defined(MOZ_WIDGET_GTK)
302 constexpr nsLiteralCString kStartupTokenNames[] = {
303 "XDG_ACTIVATION_TOKEN"_ns,
304 "DESKTOP_STARTUP_ID"_ns,
306 #endif
308 int gArgc;
309 char** gArgv;
311 static const char gToolkitVersion[] = MOZ_STRINGIFY(GRE_MILESTONE);
312 // The gToolkitBuildID global is defined to MOZ_BUILDID via gen_buildid.py
313 // in toolkit/library. See related comment in toolkit/library/moz.build.
314 extern const char gToolkitBuildID[];
316 static nsIProfileLock* gProfileLock;
317 #if defined(MOZ_HAS_REMOTE)
318 static nsRemoteService* gRemoteService;
319 bool gRestartWithoutRemote = false;
320 #endif
322 int gRestartArgc;
323 char** gRestartArgv;
325 // If gRestartedByOS is set, we were automatically restarted by the OS.
326 bool gRestartedByOS = false;
328 bool gIsGtest = false;
330 bool gKioskMode = false;
331 int gKioskMonitor = -1;
333 bool gAllowContentAnalysis = false;
335 nsString gAbsoluteArgv0Path;
337 #if defined(XP_WIN)
338 nsString gProcessStartupShortcut;
339 #endif
341 #if defined(MOZ_WIDGET_GTK)
342 # include <glib.h>
343 # include "mozilla/WidgetUtilsGtk.h"
344 # include <gtk/gtk.h>
345 # ifdef MOZ_WAYLAND
346 # include <gdk/gdkwayland.h>
347 # include "mozilla/widget/nsWaylandDisplay.h"
348 # include "wayland-proxy.h"
349 # endif
350 # ifdef MOZ_X11
351 # include <gdk/gdkx.h>
352 # endif /* MOZ_X11 */
353 #endif
355 #if defined(MOZ_WAYLAND)
356 std::unique_ptr<WaylandProxy> gWaylandProxy;
357 #endif
359 #include "BinaryPath.h"
361 #ifdef MOZ_LOGGING
362 # include "mozilla/Logging.h"
363 extern mozilla::LazyLogModule gWidgetWaylandLog;
364 #endif /* MOZ_LOGGING */
366 #ifdef FUZZING
367 # include "FuzzerRunner.h"
369 namespace mozilla {
370 FuzzerRunner* fuzzerRunner = 0;
371 } // namespace mozilla
373 # ifdef LIBFUZZER
374 void XRE_LibFuzzerSetDriver(LibFuzzerDriver aDriver) {
375 mozilla::fuzzerRunner->setParams(aDriver);
377 # endif
378 #endif // FUZZING
380 // Undo X11/X.h's definition of None
381 #undef None
383 namespace mozilla {
384 int (*RunGTest)(int*, char**) = 0;
386 bool RunningGTest() { return RunGTest; }
387 } // namespace mozilla
389 using namespace mozilla;
390 using namespace mozilla::widget;
391 using namespace mozilla::startup;
392 using mozilla::Unused;
393 using mozilla::dom::ContentChild;
394 using mozilla::dom::ContentParent;
395 using mozilla::dom::quota::QuotaManager;
396 using mozilla::intl::LocaleService;
397 using mozilla::scache::StartupCache;
399 // Save the given word to the specified environment variable.
400 static void MOZ_NEVER_INLINE SaveWordToEnv(const char* name,
401 const nsACString& word) {
402 char* expr =
403 Smprintf("%s=%s", name, PromiseFlatCString(word).get()).release();
404 if (expr) PR_SetEnv(expr);
405 // We intentionally leak |expr| here since it is required by PR_SetEnv.
408 // Save the path of the given file to the specified environment variable.
409 static void SaveFileToEnv(const char* name, nsIFile* file) {
410 #ifdef XP_WIN
411 nsAutoString path;
412 file->GetPath(path);
413 SetEnvironmentVariableW(NS_ConvertASCIItoUTF16(name).get(), path.get());
414 #else
415 nsAutoCString path;
416 file->GetNativePath(path);
417 SaveWordToEnv(name, path);
418 #endif
421 static bool gIsExpectedExit = false;
423 void MozExpectedExit() { gIsExpectedExit = true; }
426 * Runs atexit() to catch unexpected exit from 3rd party libraries like the
427 * Intel graphics driver calling exit in an error condition. When they
428 * call exit() to report an error we won't shutdown correctly and wont catch
429 * the issue with our crash reporter.
431 static void UnexpectedExit() {
432 if (!gIsExpectedExit) {
433 gIsExpectedExit = true; // Don't risk re-entrency issues when crashing.
434 MOZ_CRASH("Exit called by third party code.");
438 #if defined(MOZ_WAYLAND)
439 bool IsWaylandEnabled() {
440 static bool isWaylandEnabled = []() {
441 const char* waylandDisplay = PR_GetEnv("WAYLAND_DISPLAY");
442 if (!waylandDisplay) {
443 return false;
445 if (!PR_GetEnv("DISPLAY")) {
446 // No X11 display, so try to run wayland.
447 return true;
449 // MOZ_ENABLE_WAYLAND is our primary Wayland on/off switch.
450 if (const char* waylandPref = PR_GetEnv("MOZ_ENABLE_WAYLAND")) {
451 return *waylandPref == '1';
453 if (const char* backendPref = PR_GetEnv("GDK_BACKEND")) {
454 if (!strncmp(backendPref, "wayland", 7)) {
455 NS_WARNING(
456 "Wayland backend should be enabled by MOZ_ENABLE_WAYLAND=1."
457 "GDK_BACKEND is a Gtk3 debug variable and may cause issues.");
458 return true;
461 // Enable by default when we're running on a recent enough GTK version. We'd
462 // like to check further details like compositor version and so on ideally
463 // to make sure we don't enable it on old Mutter or what not, but we can't,
464 // so let's assume that if the user is running on a Wayland session by
465 // default we're ok, since either the distro has enabled Wayland by default,
466 // or the user has gone out of their way to use Wayland.
467 return !gtk_check_version(3, 24, 30);
468 }();
469 return isWaylandEnabled;
471 #else
472 bool IsWaylandEnabled() { return false; }
473 #endif
476 * Output a string to the user. This method is really only meant to be used to
477 * output last-ditch error messages designed for developers NOT END USERS.
479 * @param isError
480 * Pass true to indicate severe errors.
481 * @param fmt
482 * printf-style format string followed by arguments.
484 static MOZ_FORMAT_PRINTF(2, 3) void Output(bool isError, const char* fmt, ...) {
485 va_list ap;
486 va_start(ap, fmt);
488 #if defined(XP_WIN) && !MOZ_WINCONSOLE
489 SmprintfPointer msg = mozilla::Vsmprintf(fmt, ap);
490 if (msg) {
491 UINT flags = MB_OK;
492 if (isError)
493 flags |= MB_ICONERROR;
494 else
495 flags |= MB_ICONINFORMATION;
497 wchar_t wide_msg[1024];
498 MultiByteToWideChar(CP_ACP, 0, msg.get(), -1, wide_msg,
499 sizeof(wide_msg) / sizeof(wchar_t));
501 MessageBoxW(nullptr, wide_msg, L"XULRunner", flags);
503 #elif defined(MOZ_WIDGET_ANDROID)
504 SmprintfPointer msg = mozilla::Vsmprintf(fmt, ap);
505 if (msg) {
506 __android_log_print(isError ? ANDROID_LOG_ERROR : ANDROID_LOG_INFO,
507 "GeckoRuntime", "%s", msg.get());
509 #else
510 vfprintf(stderr, fmt, ap);
511 #endif
513 va_end(ap);
517 * Check for a commandline flag. If the flag takes a parameter, the
518 * parameter is returned in aParam. Flags may be in the form -arg or
519 * --arg (or /arg on win32).
521 * @param aArg the parameter to check. Must be lowercase.
522 * @param aParam if non-null, the -arg <data> will be stored in this pointer.
523 * This is *not* allocated, but rather a pointer to the argv data.
524 * @param aFlags flags @see CheckArgFlag
526 static ArgResult CheckArg(const char* aArg, const char** aParam = nullptr,
527 CheckArgFlag aFlags = CheckArgFlag::RemoveArg) {
528 MOZ_ASSERT(gArgv, "gArgv must be initialized before CheckArg()");
529 return CheckArg(gArgc, gArgv, aArg, aParam, aFlags);
533 * Check for a commandline flag. Ignore data that's passed in with the flag.
534 * Flags may be in the form -arg or --arg (or /arg on win32).
535 * Will not remove flag if found.
537 * @param aArg the parameter to check. Must be lowercase.
539 static ArgResult CheckArgExists(const char* aArg) {
540 return CheckArg(aArg, nullptr, CheckArgFlag::None);
543 bool gSafeMode = false;
544 bool gFxREmbedded = false;
546 enum E10sStatus {
547 kE10sEnabledByDefault,
548 kE10sForceDisabled,
551 static bool gBrowserTabsRemoteAutostart = false;
552 static E10sStatus gBrowserTabsRemoteStatus;
553 static bool gBrowserTabsRemoteAutostartInitialized = false;
555 namespace mozilla {
557 bool BrowserTabsRemoteAutostart() {
558 if (gBrowserTabsRemoteAutostartInitialized) {
559 return gBrowserTabsRemoteAutostart;
561 gBrowserTabsRemoteAutostartInitialized = true;
563 // If we're not in the parent process, we are running E10s.
564 if (!XRE_IsParentProcess()) {
565 gBrowserTabsRemoteAutostart = true;
566 return gBrowserTabsRemoteAutostart;
569 gBrowserTabsRemoteAutostart = true;
570 E10sStatus status = kE10sEnabledByDefault;
572 // We use "are non-local connections disabled" as a proxy for
573 // "are we running some kind of automated test". It would be nicer to use
574 // xpc::IsInAutomation(), but that depends on some prefs being set, which
575 // they are not in (at least) gtests (where we can't) and xpcshell.
576 // Long-term, hopefully we can make all tests e10s-friendly,
577 // then we could remove this automation-only env variable.
578 if (gBrowserTabsRemoteAutostart && xpc::AreNonLocalConnectionsDisabled()) {
579 const char* forceDisable = PR_GetEnv("MOZ_FORCE_DISABLE_E10S");
580 if (forceDisable && *forceDisable == '1') {
581 gBrowserTabsRemoteAutostart = false;
582 status = kE10sForceDisabled;
586 gBrowserTabsRemoteStatus = status;
588 return gBrowserTabsRemoteAutostart;
591 } // namespace mozilla
593 // Win32k Infrastructure ==============================================
595 // This bool tells us if we have initialized the following two statics
596 // upon startup.
598 static bool gWin32kInitialized = false;
600 // Win32k Lockdown for the current session is determined once, at startup,
601 // and then remains the same for the duration of the session.
603 static nsIXULRuntime::ContentWin32kLockdownState gWin32kStatus;
605 // The status of the win32k experiment. It is determined once, at startup,
606 // and then remains the same for the duration of the session.
608 static nsIXULRuntime::ExperimentStatus gWin32kExperimentStatus =
609 nsIXULRuntime::eExperimentStatusUnenrolled;
611 #ifdef XP_WIN
612 // The states for win32k lockdown can be generalized to:
613 // - User doesn't meet requirements (bad OS, webrender, remotegl) aka
614 // PersistentRequirement
615 // - User has Safe Mode enabled, Win32k Disabled by Env Var, or E10S disabled
616 // by Env Var aka TemporaryRequirement
617 // - User has set the win32k pref to something non-default aka NonDefaultPref
618 // - User has been enrolled in the experiment and does what it says aka
619 // Enrolled
620 // - User does the default aka Default
622 // We expect the below behvaior. In the code, there may be references to these
623 // behaviors (e.g. [A]) but not always.
625 // [A] Becoming enrolled in the experiment while NonDefaultPref disqualifies
626 // you upon next browser start
627 // [B] Becoming enrolled in the experiment while PersistentRequirement
628 // disqualifies you upon next browser start
629 // [C] Becoming enrolled in the experiment while TemporaryRequirement does not
630 // disqualify you
631 // [D] Becoming enrolled in the experiment will only take effect after restart
632 // [E] While enrolled, becoming PersistentRequirement will not disqualify you
633 // until browser restart, but if the state is present at browser start,
634 // will disqualify you. Additionally, it will not affect the session value
635 // of gWin32kStatus.
636 // XXX(bobowen): I hope both webrender and wbgl.out-of-process require a
637 // restart to take effect!
638 // [F] While enrolled, becoming NonDefaultPref will disqualify you upon next
639 // browser start
640 // [G] While enrolled, becoming TemporaryRequirement will _not_ disqualify you,
641 // but the session status will prevent win32k lockdown from taking effect.
643 // The win32k pref
644 static const char kPrefWin32k[] = "security.sandbox.content.win32k-disable";
646 // The current enrollment status as controlled by Normandy. This value is only
647 // stored in the default preference branch, and is not persisted across
648 // sessions by the preference service. It therefore isn't available early
649 // enough at startup, and needs to be synced to a preference in the user
650 // branch which is persisted across sessions.
651 static const char kPrefWin32kExperimentEnrollmentStatus[] =
652 "security.sandbox.content.win32k-experiment.enrollmentStatus";
654 // The enrollment status to be used at browser startup. This automatically
655 // synced from the above enrollmentStatus preference whenever the latter is
656 // changed. We reused the Fission experiment enum - it can have any of the
657 // values defined in the `nsIXULRuntime_ExperimentStatus` enum _except_ rollout.
658 // Meanings are documented in the declaration of
659 // `nsIXULRuntime.fissionExperimentStatus`
660 static const char kPrefWin32kExperimentStartupEnrollmentStatus[] =
661 "security.sandbox.content.win32k-experiment.startupEnrollmentStatus";
663 namespace mozilla {
665 bool Win32kExperimentEnrolled() {
666 MOZ_ASSERT(XRE_IsParentProcess());
667 return gWin32kExperimentStatus == nsIXULRuntime::eExperimentStatusControl ||
668 gWin32kExperimentStatus == nsIXULRuntime::eExperimentStatusTreatment;
671 } // namespace mozilla
673 static bool Win32kRequirementsUnsatisfied(
674 nsIXULRuntime::ContentWin32kLockdownState aStatus) {
675 return aStatus == nsIXULRuntime::ContentWin32kLockdownState::
676 OperatingSystemNotSupported ||
677 aStatus ==
678 nsIXULRuntime::ContentWin32kLockdownState::MissingWebRender ||
679 aStatus ==
680 nsIXULRuntime::ContentWin32kLockdownState::MissingRemoteWebGL ||
681 aStatus ==
682 nsIXULRuntime::ContentWin32kLockdownState::DecodersArentRemote;
685 static void Win32kExperimentDisqualify() {
686 MOZ_ASSERT(XRE_IsParentProcess());
687 Preferences::SetUint(kPrefWin32kExperimentEnrollmentStatus,
688 nsIXULRuntime::eExperimentStatusDisqualified);
691 static void OnWin32kEnrollmentStatusChanged(const char* aPref, void* aData) {
692 auto newStatusInt =
693 Preferences::GetUint(kPrefWin32kExperimentEnrollmentStatus,
694 nsIXULRuntime::eExperimentStatusUnenrolled);
695 auto newStatus = newStatusInt < nsIXULRuntime::eExperimentStatusCount
696 ? nsIXULRuntime::ExperimentStatus(newStatusInt)
697 : nsIXULRuntime::eExperimentStatusDisqualified;
699 // Set the startup pref for next browser start [D]
700 Preferences::SetUint(kPrefWin32kExperimentStartupEnrollmentStatus, newStatus);
703 namespace {
704 // This observer is notified during `profile-before-change`, and ensures that
705 // the experiment enrollment status is synced over before the browser shuts
706 // down, even if it was not modified since win32k was initialized.
707 class Win32kEnrollmentStatusShutdownObserver final : public nsIObserver {
708 public:
709 NS_DECL_ISUPPORTS
711 NS_IMETHOD Observe(nsISupports* aSubject, const char* aTopic,
712 const char16_t* aData) override {
713 MOZ_ASSERT(!strcmp("profile-before-change", aTopic));
714 OnWin32kEnrollmentStatusChanged(kPrefWin32kExperimentEnrollmentStatus,
715 nullptr);
716 return NS_OK;
719 private:
720 ~Win32kEnrollmentStatusShutdownObserver() = default;
722 NS_IMPL_ISUPPORTS(Win32kEnrollmentStatusShutdownObserver, nsIObserver)
723 } // namespace
725 static void OnWin32kChanged(const char* aPref, void* aData) {
726 // If we're actively enrolled in the Win32k experiment, disqualify the user
727 // from the experiment if the Win32k pref is modified. [F]
728 if (Win32kExperimentEnrolled() && Preferences::HasUserValue(kPrefWin32k)) {
729 Win32kExperimentDisqualify();
733 #endif // XP_WIN
735 namespace mozilla {
736 void EnsureWin32kInitialized();
739 nsIXULRuntime::ContentWin32kLockdownState GetLiveWin32kLockdownState() {
740 #ifdef XP_WIN
742 // HasUserValue The Pref functions can only be called on main thread
743 MOZ_ASSERT(NS_IsMainThread());
745 # ifdef MOZ_BACKGROUNDTASKS
746 if (BackgroundTasks::IsBackgroundTaskMode()) {
747 // Let's bail out before loading all the graphics libs.
748 return nsIXULRuntime::ContentWin32kLockdownState::DisabledByDefault;
750 # endif
752 mozilla::EnsureWin32kInitialized();
753 gfxPlatform::GetPlatform();
755 if (gSafeMode) {
756 return nsIXULRuntime::ContentWin32kLockdownState::DisabledBySafeMode;
759 if (EnvHasValue("MOZ_ENABLE_WIN32K")) {
760 return nsIXULRuntime::ContentWin32kLockdownState::DisabledByEnvVar;
763 if (!mozilla::BrowserTabsRemoteAutostart()) {
764 return nsIXULRuntime::ContentWin32kLockdownState::DisabledByE10S;
767 // Win32k lockdown is available on Win8+, but we are initially limiting it to
768 // Windows 10 v1709 (build 16299) or later. Before this COM initialization
769 // currently fails if user32.dll has loaded before it is called.
770 if (!IsWin10FallCreatorsUpdateOrLater()) {
771 return nsIXULRuntime::ContentWin32kLockdownState::
772 OperatingSystemNotSupported;
776 ConflictingMitigationStatus conflictingMitigationStatus = {};
777 if (!detect_win32k_conflicting_mitigations(&conflictingMitigationStatus)) {
778 return nsIXULRuntime::ContentWin32kLockdownState::
779 IncompatibleMitigationPolicy;
781 if (conflictingMitigationStatus.caller_check ||
782 conflictingMitigationStatus.sim_exec ||
783 conflictingMitigationStatus.stack_pivot) {
784 return nsIXULRuntime::ContentWin32kLockdownState::
785 IncompatibleMitigationPolicy;
789 // Non-native theming is required as well
790 if (!StaticPrefs::widget_non_native_theme_enabled()) {
791 return nsIXULRuntime::ContentWin32kLockdownState::MissingNonNativeTheming;
794 // Win32k Lockdown requires Remote WebGL, but it may be disabled on
795 // certain hardware or virtual machines.
796 if (!gfx::gfxVars::AllowWebglOop() || !StaticPrefs::webgl_out_of_process()) {
797 return nsIXULRuntime::ContentWin32kLockdownState::MissingRemoteWebGL;
800 // Some (not sure exactly which) decoders are not compatible
801 if (!PDMFactory::AllDecodersAreRemote()) {
802 return nsIXULRuntime::ContentWin32kLockdownState::DecodersArentRemote;
805 bool prefSetByUser =
806 Preferences::HasUserValue("security.sandbox.content.win32k-disable");
807 bool prefValue = Preferences::GetBool(
808 "security.sandbox.content.win32k-disable", false, PrefValueKind::User);
809 bool defaultValue = Preferences::GetBool(
810 "security.sandbox.content.win32k-disable", false, PrefValueKind::Default);
812 if (prefSetByUser) {
813 if (prefValue) {
814 return nsIXULRuntime::ContentWin32kLockdownState::EnabledByUserPref;
815 } else {
816 return nsIXULRuntime::ContentWin32kLockdownState::DisabledByUserPref;
820 if (gWin32kExperimentStatus ==
821 nsIXULRuntime::ExperimentStatus::eExperimentStatusControl) {
822 return nsIXULRuntime::ContentWin32kLockdownState::DisabledByControlGroup;
823 } else if (gWin32kExperimentStatus ==
824 nsIXULRuntime::ExperimentStatus::eExperimentStatusTreatment) {
825 return nsIXULRuntime::ContentWin32kLockdownState::EnabledByTreatmentGroup;
828 if (defaultValue) {
829 return nsIXULRuntime::ContentWin32kLockdownState::EnabledByDefault;
830 } else {
831 return nsIXULRuntime::ContentWin32kLockdownState::DisabledByDefault;
834 #else
836 return nsIXULRuntime::ContentWin32kLockdownState::OperatingSystemNotSupported;
838 #endif
841 namespace mozilla {
843 void EnsureWin32kInitialized() {
844 if (gWin32kInitialized) {
845 return;
847 gWin32kInitialized = true;
849 #ifdef XP_WIN
851 // Initialize the Win32k experiment, configuring win32k's
852 // default, before checking other overrides. This allows opting-out of a
853 // Win32k experiment through about:preferences or about:config from a
854 // safemode session.
855 uint32_t experimentRaw =
856 Preferences::GetUint(kPrefWin32kExperimentStartupEnrollmentStatus,
857 nsIXULRuntime::eExperimentStatusUnenrolled);
858 gWin32kExperimentStatus =
859 experimentRaw < nsIXULRuntime::eExperimentStatusCount
860 ? nsIXULRuntime::ExperimentStatus(experimentRaw)
861 : nsIXULRuntime::eExperimentStatusDisqualified;
863 // Watch the experiment enrollment status pref to detect experiment
864 // disqualification, and ensure it is propagated for the next restart.
865 Preferences::RegisterCallback(&OnWin32kEnrollmentStatusChanged,
866 kPrefWin32kExperimentEnrollmentStatus);
867 if (nsCOMPtr<nsIObserverService> observerService =
868 mozilla::services::GetObserverService()) {
869 nsCOMPtr<nsIObserver> shutdownObserver =
870 new Win32kEnrollmentStatusShutdownObserver();
871 observerService->AddObserver(shutdownObserver, "profile-before-change",
872 false);
875 // If the user no longer qualifies because they edited a required pref, check
876 // that. [B] [E]
877 auto tmpStatus = GetLiveWin32kLockdownState();
878 if (Win32kExperimentEnrolled() && Win32kRequirementsUnsatisfied(tmpStatus)) {
879 Win32kExperimentDisqualify();
880 gWin32kExperimentStatus = nsIXULRuntime::eExperimentStatusDisqualified;
883 // If the user has overridden an active experiment by setting a user value for
884 // "security.sandbox.content.win32k-disable", disqualify the user from the
885 // experiment. [A] [F]
886 if (Preferences::HasUserValue(kPrefWin32k) && Win32kExperimentEnrolled()) {
887 Win32kExperimentDisqualify();
888 gWin32kExperimentStatus = nsIXULRuntime::eExperimentStatusDisqualified;
891 // Unlike Fission, we do not configure the default branch based on experiment
892 // enrollment status. Instead we check the startupEnrollmentPref in
893 // GetContentWin32kLockdownState()
895 Preferences::RegisterCallback(&OnWin32kChanged, kPrefWin32k);
897 // Set the state
898 gWin32kStatus = GetLiveWin32kLockdownState();
900 #else
901 gWin32kStatus =
902 nsIXULRuntime::ContentWin32kLockdownState::OperatingSystemNotSupported;
903 gWin32kExperimentStatus = nsIXULRuntime::eExperimentStatusUnenrolled;
905 #endif // XP_WIN
908 nsIXULRuntime::ContentWin32kLockdownState GetWin32kLockdownState() {
909 #ifdef XP_WIN
911 mozilla::EnsureWin32kInitialized();
912 return gWin32kStatus;
914 #else
916 return nsIXULRuntime::ContentWin32kLockdownState::OperatingSystemNotSupported;
918 #endif
921 } // namespace mozilla
923 // End Win32k Infrastructure ==========================================
925 // Fission Infrastructure =============================================
927 // Fission enablement for the current session is determined once, at startup,
928 // and then remains the same for the duration of the session.
930 // The following factors determine whether or not Fission is enabled for a
931 // session, in order of precedence:
933 // - Safe mode: In safe mode, Fission is never enabled.
935 // - The MOZ_FORCE_ENABLE_FISSION environment variable: If set to any value,
936 // Fission will be enabled.
938 // - The 'fission.autostart' preference, if it has been configured by the user.
939 static const char kPrefFissionAutostart[] = "fission.autostart";
941 // The computed FissionAutostart value for the session, read by content
942 // processes to initialize gFissionAutostart.
944 // This pref is locked, and only configured on the default branch, so should
945 // never be persisted in a profile.
946 static const char kPrefFissionAutostartSession[] = "fission.autostart.session";
949 // The computed FissionAutostart value for the session, read by content
950 // processes to initialize gFissionAutostart.
952 static bool gFissionAutostart = false;
953 static bool gFissionAutostartInitialized = false;
954 static nsIXULRuntime::FissionDecisionStatus gFissionDecisionStatus;
955 static void EnsureFissionAutostartInitialized() {
956 if (gFissionAutostartInitialized) {
957 return;
959 gFissionAutostartInitialized = true;
961 if (!XRE_IsParentProcess()) {
962 // This pref is configured for the current session by the parent process.
963 gFissionAutostart = Preferences::GetBool(kPrefFissionAutostartSession,
964 false, PrefValueKind::Default);
965 return;
968 if (!BrowserTabsRemoteAutostart()) {
969 gFissionAutostart = false;
970 if (gBrowserTabsRemoteStatus == kE10sForceDisabled) {
971 gFissionDecisionStatus = nsIXULRuntime::eFissionDisabledByE10sEnv;
972 } else {
973 gFissionDecisionStatus = nsIXULRuntime::eFissionDisabledByE10sOther;
975 } else if (EnvHasValue("MOZ_FORCE_ENABLE_FISSION")) {
976 gFissionAutostart = true;
977 gFissionDecisionStatus = nsIXULRuntime::eFissionEnabledByEnv;
978 } else if (EnvHasValue("MOZ_FORCE_DISABLE_FISSION")) {
979 gFissionAutostart = false;
980 gFissionDecisionStatus = nsIXULRuntime::eFissionDisabledByEnv;
981 } else {
982 // NOTE: This will take into account changes to the default due to
983 // `InitializeFissionExperimentStatus`.
984 gFissionAutostart = Preferences::GetBool(kPrefFissionAutostart, false);
985 if (Preferences::HasUserValue(kPrefFissionAutostart)) {
986 gFissionDecisionStatus = gFissionAutostart
987 ? nsIXULRuntime::eFissionEnabledByUserPref
988 : nsIXULRuntime::eFissionDisabledByUserPref;
989 } else {
990 gFissionDecisionStatus = gFissionAutostart
991 ? nsIXULRuntime::eFissionEnabledByDefault
992 : nsIXULRuntime::eFissionDisabledByDefault;
996 // Content processes cannot run the same logic as we're running in the parent
997 // process, as the current value of various preferences may have changed
998 // between launches. Instead, the content process will read the default branch
999 // of the locked `fission.autostart.session` preference to determine the value
1000 // determined by this method.
1001 Preferences::Unlock(kPrefFissionAutostartSession);
1002 Preferences::ClearUser(kPrefFissionAutostartSession);
1003 Preferences::SetBool(kPrefFissionAutostartSession, gFissionAutostart,
1004 PrefValueKind::Default);
1005 Preferences::Lock(kPrefFissionAutostartSession);
1008 namespace mozilla {
1010 bool FissionAutostart() {
1011 EnsureFissionAutostartInitialized();
1012 return gFissionAutostart;
1015 } // namespace mozilla
1017 // End Fission Infrastructure =========================================
1019 namespace mozilla {
1021 bool SessionHistoryInParent() {
1022 return FissionAutostart() ||
1023 !StaticPrefs::
1024 fission_disableSessionHistoryInParent_AtStartup_DoNotUseDirectly();
1027 bool BFCacheInParent() {
1028 return SessionHistoryInParent() &&
1029 StaticPrefs::fission_bfcacheInParent_DoNotUseDirectly();
1032 } // namespace mozilla
1035 * The nsXULAppInfo object implements nsIFactory so that it can be its own
1036 * singleton.
1038 class nsXULAppInfo : public nsIXULAppInfo,
1039 #ifdef XP_WIN
1040 public nsIWinAppHelper,
1041 #endif
1042 public nsICrashReporter,
1043 public nsIFinishDumpingCallback,
1044 public nsIXULRuntime
1047 public:
1048 constexpr nsXULAppInfo() = default;
1049 NS_DECL_ISUPPORTS_INHERITED
1050 NS_DECL_NSIPLATFORMINFO
1051 NS_DECL_NSIXULAPPINFO
1052 NS_DECL_NSIXULRUNTIME
1053 NS_DECL_NSICRASHREPORTER
1054 NS_DECL_NSIFINISHDUMPINGCALLBACK
1055 #ifdef XP_WIN
1056 NS_DECL_NSIWINAPPHELPER
1057 #endif
1060 NS_INTERFACE_MAP_BEGIN(nsXULAppInfo)
1061 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXULRuntime)
1062 NS_INTERFACE_MAP_ENTRY(nsIXULRuntime)
1063 #ifdef XP_WIN
1064 NS_INTERFACE_MAP_ENTRY(nsIWinAppHelper)
1065 #endif
1066 NS_INTERFACE_MAP_ENTRY(nsICrashReporter)
1067 NS_INTERFACE_MAP_ENTRY(nsIFinishDumpingCallback)
1068 NS_INTERFACE_MAP_ENTRY(nsIPlatformInfo)
1069 NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIXULAppInfo,
1070 gAppData || XRE_IsContentProcess())
1071 NS_INTERFACE_MAP_END
1073 NS_IMETHODIMP_(MozExternalRefCountType)
1074 nsXULAppInfo::AddRef() { return 1; }
1076 NS_IMETHODIMP_(MozExternalRefCountType)
1077 nsXULAppInfo::Release() { return 1; }
1079 NS_IMETHODIMP
1080 nsXULAppInfo::GetVendor(nsACString& aResult) {
1081 if (XRE_IsContentProcess()) {
1082 ContentChild* cc = ContentChild::GetSingleton();
1083 aResult = cc->GetAppInfo().vendor;
1084 return NS_OK;
1086 aResult.Assign(gAppData->vendor);
1088 return NS_OK;
1091 NS_IMETHODIMP
1092 nsXULAppInfo::GetName(nsACString& aResult) {
1093 if (XRE_IsContentProcess()) {
1094 ContentChild* cc = ContentChild::GetSingleton();
1095 aResult = cc->GetAppInfo().name;
1096 return NS_OK;
1099 #ifdef MOZ_WIDGET_ANDROID
1100 nsCString name = java::GeckoAppShell::GetAppName()->ToCString();
1101 aResult.Assign(std::move(name));
1102 #else
1103 aResult.Assign(gAppData->name);
1104 #endif
1106 return NS_OK;
1109 NS_IMETHODIMP
1110 nsXULAppInfo::GetID(nsACString& aResult) {
1111 if (XRE_IsContentProcess()) {
1112 ContentChild* cc = ContentChild::GetSingleton();
1113 aResult = cc->GetAppInfo().ID;
1114 return NS_OK;
1116 aResult.Assign(gAppData->ID);
1118 return NS_OK;
1121 NS_IMETHODIMP
1122 nsXULAppInfo::GetVersion(nsACString& aResult) {
1123 if (XRE_IsContentProcess()) {
1124 ContentChild* cc = ContentChild::GetSingleton();
1125 aResult = cc->GetAppInfo().version;
1126 return NS_OK;
1128 aResult.Assign(gAppData->version);
1130 return NS_OK;
1133 NS_IMETHODIMP
1134 nsXULAppInfo::GetPlatformVersion(nsACString& aResult) {
1135 aResult.Assign(gToolkitVersion);
1137 return NS_OK;
1140 NS_IMETHODIMP
1141 nsXULAppInfo::GetAppBuildID(nsACString& aResult) {
1142 if (XRE_IsContentProcess()) {
1143 ContentChild* cc = ContentChild::GetSingleton();
1144 aResult = cc->GetAppInfo().buildID;
1145 return NS_OK;
1147 aResult.Assign(gAppData->buildID);
1149 return NS_OK;
1152 NS_IMETHODIMP
1153 nsXULAppInfo::GetPlatformBuildID(nsACString& aResult) {
1154 aResult.Assign(gToolkitBuildID);
1156 return NS_OK;
1159 NS_IMETHODIMP
1160 nsXULAppInfo::GetUAName(nsACString& aResult) {
1161 if (XRE_IsContentProcess()) {
1162 ContentChild* cc = ContentChild::GetSingleton();
1163 aResult = cc->GetAppInfo().UAName;
1164 return NS_OK;
1166 aResult.Assign(gAppData->UAName);
1168 return NS_OK;
1171 NS_IMETHODIMP
1172 nsXULAppInfo::GetSourceURL(nsACString& aResult) {
1173 if (XRE_IsContentProcess()) {
1174 ContentChild* cc = ContentChild::GetSingleton();
1175 aResult = cc->GetAppInfo().sourceURL;
1176 return NS_OK;
1178 aResult.Assign(gAppData->sourceURL);
1180 return NS_OK;
1183 NS_IMETHODIMP
1184 nsXULAppInfo::GetUpdateURL(nsACString& aResult) {
1185 if (XRE_IsContentProcess()) {
1186 ContentChild* cc = ContentChild::GetSingleton();
1187 aResult = cc->GetAppInfo().updateURL;
1188 return NS_OK;
1190 aResult.Assign(gAppData->updateURL);
1192 return NS_OK;
1195 NS_IMETHODIMP
1196 nsXULAppInfo::GetLogConsoleErrors(bool* aResult) {
1197 *aResult = gLogConsoleErrors;
1198 return NS_OK;
1201 NS_IMETHODIMP
1202 nsXULAppInfo::SetLogConsoleErrors(bool aValue) {
1203 gLogConsoleErrors = aValue;
1204 return NS_OK;
1207 NS_IMETHODIMP
1208 nsXULAppInfo::GetInSafeMode(bool* aResult) {
1209 *aResult = gSafeMode;
1210 return NS_OK;
1213 NS_IMETHODIMP
1214 nsXULAppInfo::GetOS(nsACString& aResult) {
1215 aResult.AssignLiteral(OS_TARGET);
1216 return NS_OK;
1219 NS_IMETHODIMP
1220 nsXULAppInfo::GetXPCOMABI(nsACString& aResult) {
1221 #ifdef TARGET_XPCOM_ABI
1222 aResult.AssignLiteral(TARGET_XPCOM_ABI);
1223 return NS_OK;
1224 #else
1225 return NS_ERROR_NOT_AVAILABLE;
1226 #endif
1229 NS_IMETHODIMP
1230 nsXULAppInfo::GetWidgetToolkit(nsACString& aResult) {
1231 aResult.AssignLiteral(MOZ_WIDGET_TOOLKIT);
1232 return NS_OK;
1235 // Ensure that the GeckoProcessType enum, defined in xpcom/build/nsXULAppAPI.h,
1236 // is synchronized with the const unsigned longs defined in
1237 // xpcom/system/nsIXULRuntime.idl.
1238 #define GECKO_PROCESS_TYPE(enum_value, enum_name, string_name, proc_typename, \
1239 process_bin_type, procinfo_typename, \
1240 webidl_typename, allcaps_name) \
1241 static_assert(nsIXULRuntime::PROCESS_TYPE_##allcaps_name == \
1242 static_cast<int>(GeckoProcessType_##enum_name), \
1243 "GeckoProcessType in nsXULAppAPI.h not synchronized with " \
1244 "nsIXULRuntime.idl");
1245 #include "mozilla/GeckoProcessTypes.h"
1246 #undef GECKO_PROCESS_TYPE
1248 // .. and ensure that that is all of them:
1249 static_assert(GeckoProcessType_Utility + 1 == GeckoProcessType_End,
1250 "Did not find the final GeckoProcessType");
1252 NS_IMETHODIMP
1253 nsXULAppInfo::GetProcessType(uint32_t* aResult) {
1254 NS_ENSURE_ARG_POINTER(aResult);
1255 *aResult = XRE_GetProcessType();
1256 return NS_OK;
1259 NS_IMETHODIMP
1260 nsXULAppInfo::GetProcessID(uint32_t* aResult) {
1261 #ifdef XP_WIN
1262 *aResult = GetCurrentProcessId();
1263 #else
1264 *aResult = getpid();
1265 #endif
1266 return NS_OK;
1269 NS_IMETHODIMP
1270 nsXULAppInfo::GetUniqueProcessID(uint64_t* aResult) {
1271 if (XRE_IsContentProcess()) {
1272 ContentChild* cc = ContentChild::GetSingleton();
1273 *aResult = cc->GetID();
1274 } else {
1275 *aResult = 0;
1277 return NS_OK;
1280 NS_IMETHODIMP
1281 nsXULAppInfo::GetRemoteType(nsACString& aRemoteType) {
1282 if (XRE_IsContentProcess()) {
1283 aRemoteType = ContentChild::GetSingleton()->GetRemoteType();
1284 } else {
1285 aRemoteType = NOT_REMOTE_TYPE;
1288 return NS_OK;
1291 static nsCString gLastAppVersion;
1292 static nsCString gLastAppBuildID;
1294 NS_IMETHODIMP
1295 nsXULAppInfo::GetLastAppVersion(nsACString& aResult) {
1296 if (XRE_IsContentProcess()) {
1297 return NS_ERROR_NOT_AVAILABLE;
1300 if (!gLastAppVersion.IsVoid() && gLastAppVersion.IsEmpty()) {
1301 NS_WARNING("Attempt to retrieve lastAppVersion before it has been set.");
1302 return NS_ERROR_NOT_AVAILABLE;
1305 aResult.Assign(gLastAppVersion);
1306 return NS_OK;
1309 NS_IMETHODIMP
1310 nsXULAppInfo::GetLastAppBuildID(nsACString& aResult) {
1311 if (XRE_IsContentProcess()) {
1312 return NS_ERROR_NOT_AVAILABLE;
1315 if (!gLastAppBuildID.IsVoid() && gLastAppBuildID.IsEmpty()) {
1316 NS_WARNING("Attempt to retrieve lastAppBuildID before it has been set.");
1317 return NS_ERROR_NOT_AVAILABLE;
1320 aResult.Assign(gLastAppBuildID);
1321 return NS_OK;
1324 NS_IMETHODIMP
1325 nsXULAppInfo::GetFissionAutostart(bool* aResult) {
1326 *aResult = FissionAutostart();
1327 return NS_OK;
1330 NS_IMETHODIMP
1331 nsXULAppInfo::GetWin32kExperimentStatus(ExperimentStatus* aResult) {
1332 if (!XRE_IsParentProcess()) {
1333 return NS_ERROR_NOT_AVAILABLE;
1336 EnsureWin32kInitialized();
1337 *aResult = gWin32kExperimentStatus;
1338 return NS_OK;
1341 NS_IMETHODIMP
1342 nsXULAppInfo::GetWin32kLiveStatusTestingOnly(
1343 nsIXULRuntime::ContentWin32kLockdownState* aResult) {
1344 if (!XRE_IsParentProcess()) {
1345 return NS_ERROR_NOT_AVAILABLE;
1348 EnsureWin32kInitialized();
1349 *aResult = GetLiveWin32kLockdownState();
1350 return NS_OK;
1353 NS_IMETHODIMP
1354 nsXULAppInfo::GetWin32kSessionStatus(
1355 nsIXULRuntime::ContentWin32kLockdownState* aResult) {
1356 if (!XRE_IsParentProcess()) {
1357 return NS_ERROR_NOT_AVAILABLE;
1360 EnsureWin32kInitialized();
1361 *aResult = gWin32kStatus;
1362 return NS_OK;
1365 NS_IMETHODIMP
1366 nsXULAppInfo::GetFissionDecisionStatus(FissionDecisionStatus* aResult) {
1367 if (!XRE_IsParentProcess()) {
1368 return NS_ERROR_NOT_AVAILABLE;
1371 EnsureFissionAutostartInitialized();
1373 MOZ_ASSERT(gFissionDecisionStatus != eFissionStatusUnknown);
1374 *aResult = gFissionDecisionStatus;
1375 return NS_OK;
1378 NS_IMETHODIMP
1379 nsXULAppInfo::GetFissionDecisionStatusString(nsACString& aResult) {
1380 if (!XRE_IsParentProcess()) {
1381 return NS_ERROR_NOT_AVAILABLE;
1384 EnsureFissionAutostartInitialized();
1385 switch (gFissionDecisionStatus) {
1386 case eFissionExperimentControl:
1387 aResult = "experimentControl";
1388 break;
1389 case eFissionExperimentTreatment:
1390 aResult = "experimentTreatment";
1391 break;
1392 case eFissionDisabledByE10sEnv:
1393 aResult = "disabledByE10sEnv";
1394 break;
1395 case eFissionEnabledByEnv:
1396 aResult = "enabledByEnv";
1397 break;
1398 case eFissionDisabledByEnv:
1399 aResult = "disabledByEnv";
1400 break;
1401 case eFissionEnabledByDefault:
1402 aResult = "enabledByDefault";
1403 break;
1404 case eFissionDisabledByDefault:
1405 aResult = "disabledByDefault";
1406 break;
1407 case eFissionEnabledByUserPref:
1408 aResult = "enabledByUserPref";
1409 break;
1410 case eFissionDisabledByUserPref:
1411 aResult = "disabledByUserPref";
1412 break;
1413 case eFissionDisabledByE10sOther:
1414 aResult = "disabledByE10sOther";
1415 break;
1416 case eFissionEnabledByRollout:
1417 aResult = "enabledByRollout";
1418 break;
1419 default:
1420 MOZ_ASSERT_UNREACHABLE("Unexpected enum value");
1422 return NS_OK;
1425 NS_IMETHODIMP
1426 nsXULAppInfo::GetSessionHistoryInParent(bool* aResult) {
1427 *aResult = SessionHistoryInParent();
1428 return NS_OK;
1431 NS_IMETHODIMP
1432 nsXULAppInfo::GetBrowserTabsRemoteAutostart(bool* aResult) {
1433 *aResult = BrowserTabsRemoteAutostart();
1434 return NS_OK;
1437 NS_IMETHODIMP
1438 nsXULAppInfo::GetMaxWebProcessCount(uint32_t* aResult) {
1439 *aResult = mozilla::GetMaxWebProcessCount();
1440 return NS_OK;
1443 NS_IMETHODIMP
1444 nsXULAppInfo::GetAccessibilityEnabled(bool* aResult) {
1445 #ifdef ACCESSIBILITY
1446 *aResult = GetAccService() != nullptr;
1447 #else
1448 *aResult = false;
1449 #endif
1450 return NS_OK;
1453 NS_IMETHODIMP
1454 nsXULAppInfo::GetAccessibilityInstantiator(nsAString& aInstantiator) {
1455 #if defined(ACCESSIBILITY) && defined(XP_WIN)
1456 if (!GetAccService()) {
1457 aInstantiator.Truncate();
1458 return NS_OK;
1460 nsAutoString ipClientInfo;
1461 a11y::Compatibility::GetHumanReadableConsumersStr(ipClientInfo);
1462 aInstantiator.Append(ipClientInfo);
1463 aInstantiator.AppendLiteral("|");
1465 nsCOMPtr<nsIFile> oopClientExe;
1466 if (a11y::GetInstantiator(getter_AddRefs(oopClientExe))) {
1467 nsAutoString oopClientInfo;
1468 if (NS_SUCCEEDED(oopClientExe->GetPath(oopClientInfo))) {
1469 aInstantiator.Append(oopClientInfo);
1472 #else
1473 aInstantiator.Truncate();
1474 #endif
1475 return NS_OK;
1478 NS_IMETHODIMP
1479 nsXULAppInfo::GetIs64Bit(bool* aResult) {
1480 #ifdef HAVE_64BIT_BUILD
1481 *aResult = true;
1482 #else
1483 *aResult = false;
1484 #endif
1485 return NS_OK;
1488 NS_IMETHODIMP
1489 nsXULAppInfo::GetIsTextRecognitionSupported(bool* aResult) {
1490 *aResult = widget::TextRecognition::IsSupported();
1491 return NS_OK;
1494 NS_IMETHODIMP
1495 nsXULAppInfo::EnsureContentProcess() {
1496 if (!XRE_IsParentProcess()) return NS_ERROR_NOT_AVAILABLE;
1498 RefPtr<ContentParent> unused =
1499 ContentParent::GetNewOrUsedBrowserProcess(DEFAULT_REMOTE_TYPE);
1500 return NS_OK;
1503 NS_IMETHODIMP
1504 nsXULAppInfo::InvalidateCachesOnRestart() {
1505 nsCOMPtr<nsIFile> file;
1506 nsresult rv =
1507 NS_GetSpecialDirectory(NS_APP_PROFILE_DIR_STARTUP, getter_AddRefs(file));
1508 if (NS_FAILED(rv)) return rv;
1509 if (!file) return NS_ERROR_NOT_AVAILABLE;
1511 file->AppendNative(FILE_COMPATIBILITY_INFO);
1513 nsINIParser parser;
1514 rv = parser.Init(file);
1515 if (NS_FAILED(rv)) {
1516 // This fails if compatibility.ini is not there, so we'll
1517 // flush the caches on the next restart anyways.
1518 return NS_OK;
1521 nsAutoCString buf;
1522 rv = parser.GetString("Compatibility", "InvalidateCaches", buf);
1524 if (NS_FAILED(rv)) {
1525 PRFileDesc* fd;
1526 rv = file->OpenNSPRFileDesc(PR_RDWR | PR_APPEND, 0600, &fd);
1527 if (NS_FAILED(rv)) {
1528 NS_ERROR("could not create output stream");
1529 return NS_ERROR_NOT_AVAILABLE;
1531 static const char kInvalidationHeader[] =
1532 NS_LINEBREAK "InvalidateCaches=1" NS_LINEBREAK;
1533 PR_Write(fd, kInvalidationHeader, sizeof(kInvalidationHeader) - 1);
1534 PR_Close(fd);
1536 return NS_OK;
1539 NS_IMETHODIMP
1540 nsXULAppInfo::GetReplacedLockTime(PRTime* aReplacedLockTime) {
1541 if (!gProfileLock) return NS_ERROR_NOT_AVAILABLE;
1542 gProfileLock->GetReplacedLockTime(aReplacedLockTime);
1543 return NS_OK;
1546 NS_IMETHODIMP
1547 nsXULAppInfo::GetDefaultUpdateChannel(nsACString& aResult) {
1548 aResult.AssignLiteral(MOZ_STRINGIFY(MOZ_UPDATE_CHANNEL));
1549 return NS_OK;
1552 NS_IMETHODIMP
1553 nsXULAppInfo::GetDistributionID(nsACString& aResult) {
1554 aResult.AssignLiteral(MOZ_DISTRIBUTION_ID);
1555 return NS_OK;
1558 NS_IMETHODIMP
1559 nsXULAppInfo::GetWindowsDLLBlocklistStatus(bool* aResult) {
1560 #if defined(HAS_DLL_BLOCKLIST)
1561 *aResult = DllBlocklist_CheckStatus();
1562 #else
1563 *aResult = false;
1564 #endif
1565 return NS_OK;
1568 NS_IMETHODIMP
1569 nsXULAppInfo::GetRestartedByOS(bool* aResult) {
1570 *aResult = gRestartedByOS;
1571 return NS_OK;
1574 NS_IMETHODIMP
1575 nsXULAppInfo::GetChromeColorSchemeIsDark(bool* aResult) {
1576 PreferenceSheet::EnsureInitialized();
1577 *aResult = PreferenceSheet::ColorSchemeForChrome() == ColorScheme::Dark;
1578 return NS_OK;
1581 NS_IMETHODIMP
1582 nsXULAppInfo::GetContentThemeDerivedColorSchemeIsDark(bool* aResult) {
1583 *aResult =
1584 PreferenceSheet::ThemeDerivedColorSchemeForContent() == ColorScheme::Dark;
1585 return NS_OK;
1588 NS_IMETHODIMP
1589 nsXULAppInfo::GetPrefersReducedMotion(bool* aResult) {
1590 *aResult =
1591 LookAndFeel::GetInt(LookAndFeel::IntID::PrefersReducedMotion, 0) == 1;
1592 return NS_OK;
1595 NS_IMETHODIMP
1596 nsXULAppInfo::GetDrawInTitlebar(bool* aResult) {
1597 *aResult = LookAndFeel::DrawInTitlebar();
1598 return NS_OK;
1601 NS_IMETHODIMP
1602 nsXULAppInfo::GetDesktopEnvironment(nsACString& aDesktopEnvironment) {
1603 #ifdef MOZ_WIDGET_GTK
1604 aDesktopEnvironment.Assign(GetDesktopEnvironmentIdentifier());
1605 #endif
1606 return NS_OK;
1609 NS_IMETHODIMP
1610 nsXULAppInfo::GetIsWayland(bool* aResult) {
1611 #ifdef MOZ_WIDGET_GTK
1612 *aResult = GdkIsWaylandDisplay();
1613 #else
1614 *aResult = false;
1615 #endif
1616 return NS_OK;
1619 NS_IMETHODIMP
1620 nsXULAppInfo::GetProcessStartupShortcut(nsAString& aShortcut) {
1621 #if defined(XP_WIN)
1622 if (XRE_IsParentProcess()) {
1623 aShortcut.Assign(gProcessStartupShortcut);
1624 return NS_OK;
1626 #endif
1627 return NS_ERROR_NOT_AVAILABLE;
1630 #if defined(XP_WIN) && defined(MOZ_LAUNCHER_PROCESS)
1631 // Forward declaration
1632 void SetupLauncherProcessPref();
1634 static Maybe<LauncherRegistryInfo::EnabledState> gLauncherProcessState;
1635 #endif // defined(XP_WIN) && defined(MOZ_LAUNCHER_PROCESS)
1637 NS_IMETHODIMP
1638 nsXULAppInfo::GetLauncherProcessState(uint32_t* aResult) {
1639 #if defined(XP_WIN) && defined(MOZ_LAUNCHER_PROCESS)
1640 SetupLauncherProcessPref();
1642 if (!gLauncherProcessState) {
1643 return NS_ERROR_UNEXPECTED;
1646 *aResult = static_cast<uint32_t>(gLauncherProcessState.value());
1647 return NS_OK;
1648 #else
1649 return NS_ERROR_NOT_AVAILABLE;
1650 #endif
1653 #ifdef XP_WIN
1654 NS_IMETHODIMP
1655 nsXULAppInfo::GetUserCanElevate(bool* aUserCanElevate) {
1656 HANDLE rawToken;
1657 if (!::OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY, &rawToken)) {
1658 *aUserCanElevate = false;
1659 return NS_OK;
1662 nsAutoHandle token(rawToken);
1663 LauncherResult<TOKEN_ELEVATION_TYPE> elevationType = GetElevationType(token);
1664 if (elevationType.isErr()) {
1665 *aUserCanElevate = false;
1666 return NS_OK;
1669 // The possible values returned for elevationType and their meanings are:
1670 // TokenElevationTypeDefault: The token does not have a linked token
1671 // (e.g. UAC disabled or a standard user, so they can't be elevated)
1672 // TokenElevationTypeFull: The token is linked to an elevated token
1673 // (e.g. UAC is enabled and the user is already elevated so they can't
1674 // be elevated again)
1675 // TokenElevationTypeLimited: The token is linked to a limited token
1676 // (e.g. UAC is enabled and the user is not elevated, so they can be
1677 // elevated)
1678 *aUserCanElevate = (elevationType.inspect() == TokenElevationTypeLimited);
1679 return NS_OK;
1681 #endif
1683 NS_IMETHODIMP
1684 nsXULAppInfo::GetCrashReporterEnabled(bool* aEnabled) {
1685 *aEnabled = CrashReporter::GetEnabled();
1686 return NS_OK;
1689 NS_IMETHODIMP
1690 nsXULAppInfo::SetEnabled(bool aEnabled) {
1691 if (aEnabled) {
1692 if (CrashReporter::GetEnabled()) {
1693 // no point in erroring for double-enabling
1694 return NS_OK;
1697 nsCOMPtr<nsIFile> greBinDir;
1698 NS_GetSpecialDirectory(NS_GRE_BIN_DIR, getter_AddRefs(greBinDir));
1699 if (!greBinDir) {
1700 return NS_ERROR_FAILURE;
1703 nsCOMPtr<nsIFile> xreBinDirectory = greBinDir;
1704 if (!xreBinDirectory) {
1705 return NS_ERROR_FAILURE;
1708 return CrashReporter::SetExceptionHandler(xreBinDirectory, true);
1711 if (!CrashReporter::GetEnabled()) {
1712 // no point in erroring for double-disabling
1713 return NS_OK;
1716 return CrashReporter::UnsetExceptionHandler();
1719 NS_IMETHODIMP
1720 nsXULAppInfo::GetServerURL(nsIURL** aServerURL) {
1721 NS_ENSURE_ARG_POINTER(aServerURL);
1722 if (!CrashReporter::GetEnabled()) return NS_ERROR_NOT_INITIALIZED;
1724 nsAutoCString data;
1725 if (!CrashReporter::GetServerURL(data)) {
1726 return NS_ERROR_FAILURE;
1728 nsCOMPtr<nsIURI> uri;
1729 NS_NewURI(getter_AddRefs(uri), data);
1730 if (!uri) return NS_ERROR_FAILURE;
1732 nsCOMPtr<nsIURL> url;
1733 url = do_QueryInterface(uri);
1734 NS_ADDREF(*aServerURL = url);
1736 return NS_OK;
1739 NS_IMETHODIMP
1740 nsXULAppInfo::SetServerURL(nsIURL* aServerURL) {
1741 // Only allow https or http URLs
1742 if (!aServerURL->SchemeIs("http") && !aServerURL->SchemeIs("https")) {
1743 return NS_ERROR_INVALID_ARG;
1746 nsAutoCString spec;
1747 nsresult rv = aServerURL->GetSpec(spec);
1748 NS_ENSURE_SUCCESS(rv, rv);
1750 return CrashReporter::SetServerURL(spec);
1753 NS_IMETHODIMP
1754 nsXULAppInfo::GetMinidumpPath(nsIFile** aMinidumpPath) {
1755 if (!CrashReporter::GetEnabled()) return NS_ERROR_NOT_INITIALIZED;
1757 nsAutoString path;
1758 if (!CrashReporter::GetMinidumpPath(path)) return NS_ERROR_FAILURE;
1760 nsresult rv = NS_NewLocalFile(path, false, aMinidumpPath);
1761 NS_ENSURE_SUCCESS(rv, rv);
1762 return NS_OK;
1765 NS_IMETHODIMP
1766 nsXULAppInfo::SetMinidumpPath(nsIFile* aMinidumpPath) {
1767 nsAutoString path;
1768 nsresult rv = aMinidumpPath->GetPath(path);
1769 NS_ENSURE_SUCCESS(rv, rv);
1770 return CrashReporter::SetMinidumpPath(path);
1773 NS_IMETHODIMP
1774 nsXULAppInfo::GetMinidumpForID(const nsAString& aId, nsIFile** aMinidump) {
1775 if (!CrashReporter::GetMinidumpForID(aId, aMinidump)) {
1776 return NS_ERROR_FILE_NOT_FOUND;
1779 return NS_OK;
1782 NS_IMETHODIMP
1783 nsXULAppInfo::GetExtraFileForID(const nsAString& aId, nsIFile** aExtraFile) {
1784 if (!CrashReporter::GetExtraFileForID(aId, aExtraFile)) {
1785 return NS_ERROR_FILE_NOT_FOUND;
1788 return NS_OK;
1791 NS_IMETHODIMP
1792 nsXULAppInfo::AnnotateCrashReport(const nsACString& key,
1793 const nsACString& data) {
1794 CrashReporter::Annotation annotation;
1796 if (!AnnotationFromString(annotation, PromiseFlatCString(key).get())) {
1797 return NS_ERROR_INVALID_ARG;
1800 return CrashReporter::AnnotateCrashReport(annotation, data);
1803 NS_IMETHODIMP
1804 nsXULAppInfo::RemoveCrashReportAnnotation(const nsACString& key) {
1805 CrashReporter::Annotation annotation;
1807 if (!AnnotationFromString(annotation, PromiseFlatCString(key).get())) {
1808 return NS_ERROR_INVALID_ARG;
1811 return CrashReporter::RemoveCrashReportAnnotation(annotation);
1814 NS_IMETHODIMP
1815 nsXULAppInfo::IsAnnotationAllowedForPing(const nsACString& aValue,
1816 bool* aIsAllowed) {
1817 CrashReporter::Annotation annotation;
1819 if (!AnnotationFromString(annotation, PromiseFlatCString(aValue).get())) {
1820 return NS_ERROR_INVALID_ARG;
1823 *aIsAllowed = CrashReporter::IsAnnotationAllowedForPing(annotation);
1825 return NS_OK;
1828 NS_IMETHODIMP
1829 nsXULAppInfo::AppendAppNotesToCrashReport(const nsACString& data) {
1830 return CrashReporter::AppendAppNotesToCrashReport(data);
1833 NS_IMETHODIMP
1834 nsXULAppInfo::RegisterAppMemory(uint64_t pointer, uint64_t len) {
1835 return CrashReporter::RegisterAppMemory((void*)pointer, len);
1838 NS_IMETHODIMP
1839 nsXULAppInfo::WriteMinidumpForException(void* aExceptionInfo) {
1840 #ifdef XP_WIN
1841 return CrashReporter::WriteMinidumpForException(
1842 static_cast<EXCEPTION_POINTERS*>(aExceptionInfo));
1843 #else
1844 return NS_ERROR_NOT_IMPLEMENTED;
1845 #endif
1848 NS_IMETHODIMP
1849 nsXULAppInfo::AppendObjCExceptionInfoToAppNotes(void* aException) {
1850 #ifdef XP_MACOSX
1851 return CrashReporter::AppendObjCExceptionInfoToAppNotes(aException);
1852 #else
1853 return NS_ERROR_NOT_IMPLEMENTED;
1854 #endif
1857 NS_IMETHODIMP
1858 nsXULAppInfo::GetSubmitReports(bool* aEnabled) {
1859 return CrashReporter::GetSubmitReports(aEnabled);
1862 NS_IMETHODIMP
1863 nsXULAppInfo::SetSubmitReports(bool aEnabled) {
1864 return CrashReporter::SetSubmitReports(aEnabled);
1867 NS_IMETHODIMP
1868 nsXULAppInfo::UpdateCrashEventsDir() {
1869 CrashReporter::UpdateCrashEventsDir();
1870 return NS_OK;
1873 NS_IMETHODIMP
1874 nsXULAppInfo::SaveMemoryReport() {
1875 if (!CrashReporter::GetEnabled()) {
1876 return NS_ERROR_NOT_INITIALIZED;
1878 nsCOMPtr<nsIFile> file;
1879 nsresult rv = CrashReporter::GetDefaultMemoryReportFile(getter_AddRefs(file));
1880 if (NS_WARN_IF(NS_FAILED(rv))) {
1881 return rv;
1884 nsString path;
1885 file->GetPath(path);
1887 nsCOMPtr<nsIMemoryInfoDumper> dumper =
1888 do_GetService("@mozilla.org/memory-info-dumper;1");
1889 if (NS_WARN_IF(!dumper)) {
1890 return NS_ERROR_UNEXPECTED;
1893 rv = dumper->DumpMemoryReportsToNamedFile(
1894 path, this, file, true /* anonymize */, false /* minimizeMemoryUsage */);
1895 if (NS_WARN_IF(NS_FAILED(rv))) {
1896 return rv;
1898 return NS_OK;
1901 // This method is from nsIFInishDumpingCallback.
1902 NS_IMETHODIMP
1903 nsXULAppInfo::Callback(nsISupports* aData) {
1904 nsCOMPtr<nsIFile> file = do_QueryInterface(aData);
1905 MOZ_ASSERT(file);
1907 CrashReporter::SetMemoryReportFile(file);
1908 return NS_OK;
1911 static const nsXULAppInfo kAppInfo;
1912 namespace mozilla {
1913 nsresult AppInfoConstructor(REFNSIID aIID, void** aResult) {
1914 return const_cast<nsXULAppInfo*>(&kAppInfo)->QueryInterface(aIID, aResult);
1916 } // namespace mozilla
1918 bool gLogConsoleErrors = false;
1920 #define NS_ENSURE_TRUE_LOG(x, ret) \
1921 PR_BEGIN_MACRO \
1922 if (MOZ_UNLIKELY(!(x))) { \
1923 NS_WARNING("NS_ENSURE_TRUE(" #x ") failed"); \
1924 gLogConsoleErrors = true; \
1925 return ret; \
1927 PR_END_MACRO
1929 #define NS_ENSURE_SUCCESS_LOG(res, ret) \
1930 NS_ENSURE_TRUE_LOG(NS_SUCCEEDED(res), ret)
1933 * Because we're starting/stopping XPCOM several times in different scenarios,
1934 * this class is a stack-based critter that makes sure that XPCOM is shut down
1935 * during early returns.
1938 class ScopedXPCOMStartup {
1939 public:
1940 ScopedXPCOMStartup() : mServiceManager(nullptr) {}
1941 ~ScopedXPCOMStartup();
1943 nsresult Initialize(bool aInitJSContext = true);
1944 nsresult SetWindowCreator(nsINativeAppSupport* native);
1946 private:
1947 nsIServiceManager* mServiceManager;
1948 static nsINativeAppSupport* gNativeAppSupport;
1950 friend already_AddRefed<nsINativeAppSupport> NS_GetNativeAppSupport();
1953 ScopedXPCOMStartup::~ScopedXPCOMStartup() {
1954 NS_IF_RELEASE(gNativeAppSupport);
1956 if (mServiceManager) {
1957 #ifdef XP_MACOSX
1958 // On OS X, we need a pool to catch cocoa objects that are autoreleased
1959 // during teardown.
1960 mozilla::MacAutoreleasePool pool;
1961 #endif
1963 nsCOMPtr<nsIAppStartup> appStartup(components::AppStartup::Service());
1964 if (appStartup) appStartup->DestroyHiddenWindow();
1966 gDirServiceProvider->DoShutdown();
1967 PROFILER_MARKER_UNTYPED("Shutdown early", OTHER);
1969 WriteConsoleLog();
1971 NS_ShutdownXPCOM(mServiceManager);
1972 mServiceManager = nullptr;
1976 nsresult ScopedXPCOMStartup::Initialize(bool aInitJSContext) {
1977 NS_ASSERTION(gDirServiceProvider, "Should not get here!");
1979 nsresult rv;
1981 rv = NS_InitXPCOM(&mServiceManager, gDirServiceProvider->GetAppDir(),
1982 gDirServiceProvider, aInitJSContext);
1983 if (NS_FAILED(rv)) {
1984 NS_ERROR("Couldn't start xpcom!");
1985 mServiceManager = nullptr;
1986 } else {
1987 #ifdef DEBUG
1988 nsCOMPtr<nsIComponentRegistrar> reg = do_QueryInterface(mServiceManager);
1989 NS_ASSERTION(reg, "Service Manager doesn't QI to Registrar.");
1990 #endif
1993 return rv;
1997 * This is a little factory class that serves as a singleton-service-factory
1998 * for the nativeappsupport object.
2000 class nsSingletonFactory final : public nsIFactory {
2001 public:
2002 NS_DECL_ISUPPORTS
2003 NS_DECL_NSIFACTORY
2005 explicit nsSingletonFactory(nsISupports* aSingleton);
2007 private:
2008 ~nsSingletonFactory() = default;
2009 nsCOMPtr<nsISupports> mSingleton;
2012 nsSingletonFactory::nsSingletonFactory(nsISupports* aSingleton)
2013 : mSingleton(aSingleton) {
2014 NS_ASSERTION(mSingleton, "Singleton was null!");
2017 NS_IMPL_ISUPPORTS(nsSingletonFactory, nsIFactory)
2019 NS_IMETHODIMP
2020 nsSingletonFactory::CreateInstance(const nsIID& aIID, void** aResult) {
2021 return mSingleton->QueryInterface(aIID, aResult);
2025 * Set our windowcreator on the WindowWatcher service.
2027 nsresult ScopedXPCOMStartup::SetWindowCreator(nsINativeAppSupport* native) {
2028 nsresult rv;
2030 NS_IF_ADDREF(gNativeAppSupport = native);
2032 nsCOMPtr<nsIWindowCreator> creator(components::AppStartup::Service());
2033 if (!creator) return NS_ERROR_UNEXPECTED;
2035 nsCOMPtr<nsIWindowWatcher> wwatch(
2036 do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv));
2037 NS_ENSURE_SUCCESS(rv, rv);
2039 return wwatch->SetWindowCreator(creator);
2042 /* static */ already_AddRefed<nsINativeAppSupport> NS_GetNativeAppSupport() {
2043 if (!ScopedXPCOMStartup::gNativeAppSupport) {
2044 return nullptr;
2047 return do_AddRef(ScopedXPCOMStartup::gNativeAppSupport);
2050 nsINativeAppSupport* ScopedXPCOMStartup::gNativeAppSupport;
2052 static void DumpArbitraryHelp() {
2053 nsresult rv;
2055 ScopedLogging log;
2058 ScopedXPCOMStartup xpcom;
2059 xpcom.Initialize();
2061 nsCOMPtr<nsICommandLineRunner> cmdline(new nsCommandLine());
2063 nsCString text;
2064 rv = cmdline->GetHelpText(text);
2065 if (NS_SUCCEEDED(rv)) printf("%s", text.get());
2069 // English text needs to go into a dtd file.
2070 // But when this is called we have no components etc. These strings must either
2071 // be here, or in a native resource file.
2072 static void DumpHelp() {
2073 printf(
2074 "Usage: %s [ options ... ] [URL]\n"
2075 " where options include:\n\n",
2076 gArgv[0]);
2078 #ifdef MOZ_X11
2079 printf(
2080 "X11 options\n"
2081 " --display=DISPLAY X display to use\n"
2082 " --sync Make X calls synchronous\n");
2083 #endif
2084 #ifdef XP_UNIX
2085 printf(
2086 " --g-fatal-warnings Make all warnings fatal\n"
2087 "\n%s options\n",
2088 (const char*)gAppData->name);
2089 #endif
2091 printf(
2092 " -h or --help Print this message.\n"
2093 " -v or --version Print %s version.\n"
2094 " --full-version Print %s version, build and platform build ids.\n"
2095 " -P <profile> Start with <profile>.\n"
2096 " --profile <path> Start with profile at <path>.\n"
2097 " --migration Start with migration wizard.\n"
2098 " --ProfileManager Start with ProfileManager.\n"
2099 #ifdef MOZ_HAS_REMOTE
2100 " --no-remote Do not accept or send remote commands; implies\n"
2101 " --new-instance.\n"
2102 " --new-instance Open new instance, not a new window in running "
2103 "instance.\n"
2104 #endif
2105 " --safe-mode Disables extensions and themes for this session.\n"
2106 #ifdef MOZ_BLOCK_PROFILE_DOWNGRADE
2107 " --allow-downgrade Allows downgrading a profile.\n"
2108 #endif
2109 " --MOZ_LOG=<modules> Treated as MOZ_LOG=<modules> environment "
2110 "variable,\n"
2111 " overrides it.\n"
2112 " --MOZ_LOG_FILE=<file> Treated as MOZ_LOG_FILE=<file> environment "
2113 "variable,\n"
2114 " overrides it. If MOZ_LOG_FILE is not specified as "
2115 "an\n"
2116 " argument or as an environment variable, logging "
2117 "will be\n"
2118 " written to stdout.\n",
2119 (const char*)gAppData->name, (const char*)gAppData->name);
2121 #if defined(XP_WIN)
2122 printf(" --console Start %s with a debugging console.\n",
2123 (const char*)gAppData->name);
2124 #endif
2126 #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) || defined(XP_MACOSX)
2127 printf(" --headless Run without a GUI.\n");
2128 #endif
2130 // this works, but only after the components have registered. so if you drop
2131 // in a new command line handler, --help won't not until the second run. out
2132 // of the bug, because we ship a component.reg file, it works correctly.
2133 DumpArbitraryHelp();
2136 static inline void DumpVersion() {
2137 if (gAppData->vendor && *gAppData->vendor) {
2138 printf("%s ", (const char*)gAppData->vendor);
2140 printf("%s ", (const char*)gAppData->name);
2142 // Use the displayed version
2143 // For example, for beta, we would display 42.0b2 instead of 42.0
2144 printf("%s", MOZ_STRINGIFY(MOZ_APP_VERSION_DISPLAY));
2146 if (gAppData->copyright && *gAppData->copyright) {
2147 printf(", %s", (const char*)gAppData->copyright);
2149 printf("\n");
2152 static inline void DumpFullVersion() {
2153 if (gAppData->vendor && *gAppData->vendor) {
2154 printf("%s ", (const char*)gAppData->vendor);
2156 printf("%s ", (const char*)gAppData->name);
2158 // Use the displayed version
2159 // For example, for beta, we would display 42.0b2 instead of 42.0
2160 printf("%s ", MOZ_STRINGIFY(MOZ_APP_VERSION_DISPLAY));
2162 printf("%s ", (const char*)gAppData->buildID);
2163 printf("%s ", (const char*)PlatformBuildID());
2164 if (gAppData->copyright && *gAppData->copyright) {
2165 printf(", %s", (const char*)gAppData->copyright);
2167 printf("\n");
2170 void XRE_InitOmnijar(nsIFile* greOmni, nsIFile* appOmni) {
2171 mozilla::Omnijar::Init(greOmni, appOmni);
2174 nsresult XRE_GetBinaryPath(nsIFile** aResult) {
2175 return mozilla::BinaryPath::GetFile(aResult);
2178 #ifdef XP_WIN
2179 # include "nsWindowsRestart.cpp"
2180 # include <shellapi.h>
2182 typedef BOOL(WINAPI* SetProcessDEPPolicyFunc)(DWORD dwFlags);
2184 static void RegisterApplicationRestartChanged(const char* aPref, void* aData) {
2185 DWORD cchCmdLine = 0;
2186 HRESULT rc = ::GetApplicationRestartSettings(::GetCurrentProcess(), nullptr,
2187 &cchCmdLine, nullptr);
2188 bool wasRegistered = false;
2189 if (rc == S_OK) {
2190 wasRegistered = true;
2193 if (Preferences::GetBool(PREF_WIN_REGISTER_APPLICATION_RESTART, false) &&
2194 !wasRegistered) {
2195 // Make the command line to use when restarting.
2196 // Excludes argv[0] because RegisterApplicationRestart adds the
2197 // executable name, replace that temporarily with -os-restarted
2198 char* exeName = gRestartArgv[0];
2199 gRestartArgv[0] = const_cast<char*>("-os-restarted");
2200 wchar_t** restartArgvConverted =
2201 AllocConvertUTF8toUTF16Strings(gRestartArgc, gRestartArgv);
2202 gRestartArgv[0] = exeName;
2204 mozilla::UniquePtr<wchar_t[]> restartCommandLine;
2205 if (restartArgvConverted) {
2206 restartCommandLine =
2207 mozilla::MakeCommandLine(gRestartArgc, restartArgvConverted);
2208 FreeAllocStrings(gRestartArgc, restartArgvConverted);
2211 if (restartCommandLine) {
2212 // Flags RESTART_NO_PATCH and RESTART_NO_REBOOT are not set, so we
2213 // should be restarted if terminated by an update or restart.
2214 ::RegisterApplicationRestart(restartCommandLine.get(),
2215 RESTART_NO_CRASH | RESTART_NO_HANG);
2217 } else if (wasRegistered) {
2218 ::UnregisterApplicationRestart();
2222 static void OnAlteredPrefetchPrefChanged(const char* aPref, void* aData) {
2223 int32_t prefVal = Preferences::GetInt(PREF_WIN_ALTERED_DLL_PREFETCH, 0);
2225 mozilla::DllPrefetchExperimentRegistryInfo prefetchRegInfo;
2226 mozilla::DebugOnly<mozilla::Result<Ok, nsresult>> reflectResult =
2227 prefetchRegInfo.ReflectPrefToRegistry(prefVal);
2229 MOZ_ASSERT(reflectResult.value.isOk());
2232 static void SetupAlteredPrefetchPref() {
2233 mozilla::DllPrefetchExperimentRegistryInfo prefetchRegInfo;
2235 mozilla::DebugOnly<mozilla::Result<Ok, nsresult>> reflectResult =
2236 prefetchRegInfo.ReflectPrefToRegistry(
2237 Preferences::GetInt(PREF_WIN_ALTERED_DLL_PREFETCH, 0));
2238 MOZ_ASSERT(reflectResult.value.isOk());
2240 Preferences::RegisterCallback(&OnAlteredPrefetchPrefChanged,
2241 PREF_WIN_ALTERED_DLL_PREFETCH);
2244 static void ReflectSkeletonUIPrefToRegistry(const char* aPref, void* aData) {
2245 Unused << aPref;
2246 Unused << aData;
2248 bool shouldBeEnabled =
2249 Preferences::GetBool(kPrefPreXulSkeletonUI, false) &&
2250 Preferences::GetBool(kPrefBrowserStartupBlankWindow, false) &&
2251 LookAndFeel::DrawInTitlebar();
2252 if (shouldBeEnabled && Preferences::HasUserValue(kPrefThemeId)) {
2253 nsCString themeId;
2254 Preferences::GetCString(kPrefThemeId, themeId);
2255 if (themeId.EqualsLiteral("default-theme@mozilla.org")) {
2256 Unused << SetPreXULSkeletonUIThemeId(ThemeMode::Default);
2257 } else if (themeId.EqualsLiteral("firefox-compact-dark@mozilla.org")) {
2258 Unused << SetPreXULSkeletonUIThemeId(ThemeMode::Dark);
2259 } else if (themeId.EqualsLiteral("firefox-compact-light@mozilla.org")) {
2260 Unused << SetPreXULSkeletonUIThemeId(ThemeMode::Light);
2261 } else {
2262 shouldBeEnabled = false;
2264 } else if (shouldBeEnabled) {
2265 Unused << SetPreXULSkeletonUIThemeId(ThemeMode::Default);
2268 if (GetPreXULSkeletonUIEnabled() != shouldBeEnabled) {
2269 Unused << SetPreXULSkeletonUIEnabledIfAllowed(shouldBeEnabled);
2273 static void SetupSkeletonUIPrefs() {
2274 ReflectSkeletonUIPrefToRegistry(nullptr, nullptr);
2275 Preferences::RegisterCallback(&ReflectSkeletonUIPrefToRegistry,
2276 kPrefPreXulSkeletonUI);
2277 Preferences::RegisterCallback(&ReflectSkeletonUIPrefToRegistry,
2278 kPrefBrowserStartupBlankWindow);
2279 Preferences::RegisterCallback(&ReflectSkeletonUIPrefToRegistry, kPrefThemeId);
2280 Preferences::RegisterCallback(
2281 &ReflectSkeletonUIPrefToRegistry,
2282 nsDependentCString(StaticPrefs::GetPrefName_browser_tabs_inTitlebar()));
2285 # if defined(MOZ_LAUNCHER_PROCESS)
2287 static void OnLauncherPrefChanged(const char* aPref, void* aData) {
2288 bool prefVal = Preferences::GetBool(PREF_WIN_LAUNCHER_PROCESS_ENABLED, true);
2290 mozilla::LauncherRegistryInfo launcherRegInfo;
2291 mozilla::DebugOnly<mozilla::LauncherVoidResult> reflectResult =
2292 launcherRegInfo.ReflectPrefToRegistry(prefVal);
2293 MOZ_ASSERT(reflectResult.inspect().isOk());
2296 static void OnLauncherTelemetryPrefChanged(const char* aPref, void* aData) {
2297 bool prefVal = Preferences::GetBool(kPrefHealthReportUploadEnabled, true);
2299 mozilla::LauncherRegistryInfo launcherRegInfo;
2300 mozilla::DebugOnly<mozilla::LauncherVoidResult> reflectResult =
2301 launcherRegInfo.ReflectTelemetryPrefToRegistry(prefVal);
2302 MOZ_ASSERT(reflectResult.inspect().isOk());
2305 static void SetupLauncherProcessPref() {
2306 if (gLauncherProcessState) {
2307 // We've already successfully run
2308 return;
2311 mozilla::LauncherRegistryInfo launcherRegInfo;
2313 mozilla::LauncherResult<mozilla::LauncherRegistryInfo::EnabledState>
2314 enabledState = launcherRegInfo.IsEnabled();
2316 if (enabledState.isOk()) {
2317 gLauncherProcessState = Some(enabledState.unwrap());
2319 CrashReporter::AnnotateCrashReport(
2320 CrashReporter::Annotation::LauncherProcessState,
2321 static_cast<uint32_t>(enabledState.unwrap()));
2323 // Reflect the launcher process registry state into user prefs
2324 Preferences::SetBool(
2325 PREF_WIN_LAUNCHER_PROCESS_ENABLED,
2326 enabledState.unwrap() !=
2327 mozilla::LauncherRegistryInfo::EnabledState::ForceDisabled);
2330 mozilla::DebugOnly<mozilla::LauncherVoidResult> reflectResult =
2331 launcherRegInfo.ReflectTelemetryPrefToRegistry(
2332 Preferences::GetBool(kPrefHealthReportUploadEnabled, true));
2333 MOZ_ASSERT(reflectResult.inspect().isOk());
2335 Preferences::RegisterCallback(&OnLauncherPrefChanged,
2336 PREF_WIN_LAUNCHER_PROCESS_ENABLED);
2337 Preferences::RegisterCallback(&OnLauncherTelemetryPrefChanged,
2338 kPrefHealthReportUploadEnabled);
2341 # endif // defined(MOZ_LAUNCHER_PROCESS)
2343 # if defined(MOZ_DEFAULT_BROWSER_AGENT)
2345 # define DEFAULT_BROWSER_AGENT_KEY_NAME \
2346 "SOFTWARE\\" MOZ_APP_VENDOR "\\" MOZ_APP_NAME "\\Default Browser Agent"
2348 static nsresult PrependRegistryValueName(nsAutoString& aValueName) {
2349 nsresult rv;
2351 nsCOMPtr<nsIFile> binaryPath;
2352 rv = XRE_GetBinaryPath(getter_AddRefs(binaryPath));
2353 NS_ENSURE_SUCCESS(rv, rv);
2355 nsCOMPtr<nsIFile> binaryDir;
2356 rv = binaryPath->GetParent(getter_AddRefs(binaryDir));
2357 NS_ENSURE_SUCCESS(rv, rv);
2359 nsAutoString prefix;
2360 rv = binaryDir->GetPath(prefix);
2361 NS_ENSURE_SUCCESS(rv, rv);
2363 prefix.AppendLiteral("|");
2364 aValueName.Insert(prefix, 0);
2366 return NS_OK;
2369 static void OnDefaultAgentTelemetryPrefChanged(const char* aPref, void* aData) {
2370 nsresult rv;
2371 nsAutoString valueName;
2372 if (strcmp(aPref, kPrefHealthReportUploadEnabled) == 0) {
2373 valueName.AssignLiteral("DisableTelemetry");
2374 } else if (strcmp(aPref, kPrefDefaultAgentEnabled) == 0) {
2375 valueName.AssignLiteral("DisableDefaultBrowserAgent");
2376 } else {
2377 return;
2379 rv = PrependRegistryValueName(valueName);
2380 NS_ENSURE_SUCCESS_VOID(rv);
2382 nsCOMPtr<nsIWindowsRegKey> regKey =
2383 do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv);
2384 NS_ENSURE_SUCCESS_VOID(rv);
2386 nsAutoString keyName;
2387 keyName.AppendLiteral(DEFAULT_BROWSER_AGENT_KEY_NAME);
2388 rv = regKey->Create(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER, keyName,
2389 nsIWindowsRegKey::ACCESS_WRITE);
2391 bool prefVal = Preferences::GetBool(aPref, true);
2393 // We're recording whether the pref is *disabled*, so invert the value.
2394 rv = regKey->WriteIntValue(valueName, prefVal ? 0 : 1);
2395 NS_ENSURE_SUCCESS_VOID(rv);
2398 static void OnSetDefaultBrowserUserChoicePrefChanged(const char* aPref,
2399 void* aData) {
2400 nsresult rv;
2401 if (strcmp(aPref, kPrefSetDefaultBrowserUserChoicePref) != 0) {
2402 return;
2404 nsAutoString valueName;
2405 valueName.AssignLiteral("SetDefaultBrowserUserChoice");
2406 rv = PrependRegistryValueName(valueName);
2407 NS_ENSURE_SUCCESS_VOID(rv);
2409 nsCOMPtr<nsIWindowsRegKey> regKey =
2410 do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv);
2411 NS_ENSURE_SUCCESS_VOID(rv);
2413 nsAutoString keyName;
2414 keyName.AppendLiteral(DEFAULT_BROWSER_AGENT_KEY_NAME);
2415 rv = regKey->Create(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER, keyName,
2416 nsIWindowsRegKey::ACCESS_WRITE);
2418 bool prefVal = Preferences::GetBool(aPref, true);
2420 rv = regKey->WriteIntValue(valueName, prefVal);
2421 NS_ENSURE_SUCCESS_VOID(rv);
2424 static void OnDefaultAgentRemoteSettingsPrefChanged(const char* aPref,
2425 void* aData) {
2426 nsresult rv;
2427 nsAutoString valueName;
2428 if (strcmp(aPref, kPrefServicesSettingsServer) == 0) {
2429 valueName.AssignLiteral("ServicesSettingsServer");
2430 } else if (strcmp(aPref, kPrefSecurityContentSignatureRootHash) == 0) {
2431 valueName.AssignLiteral("SecurityContentSignatureRootHash");
2432 } else {
2433 return;
2435 rv = PrependRegistryValueName(valueName);
2436 NS_ENSURE_SUCCESS_VOID(rv);
2438 nsCOMPtr<nsIWindowsRegKey> regKey =
2439 do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv);
2440 NS_ENSURE_SUCCESS_VOID(rv);
2442 nsAutoString keyName;
2443 keyName.AppendLiteral(DEFAULT_BROWSER_AGENT_KEY_NAME);
2444 rv = regKey->Create(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER, keyName,
2445 nsIWindowsRegKey::ACCESS_WRITE);
2447 NS_ENSURE_SUCCESS_VOID(rv);
2449 nsAutoString prefVal;
2450 rv = Preferences::GetString(aPref, prefVal);
2451 if (NS_FAILED(rv)) {
2452 return;
2455 if (prefVal.IsEmpty()) {
2456 rv = regKey->RemoveValue(valueName);
2457 } else {
2458 rv = regKey->WriteStringValue(valueName, prefVal);
2460 NS_ENSURE_SUCCESS_VOID(rv);
2463 static void SetDefaultAgentLastRunTime() {
2464 nsresult rv;
2465 nsAutoString valueName;
2466 valueName.AppendLiteral("AppLastRunTime");
2467 rv = PrependRegistryValueName(valueName);
2468 NS_ENSURE_SUCCESS_VOID(rv);
2470 nsCOMPtr<nsIWindowsRegKey> regKey =
2471 do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv);
2472 NS_ENSURE_SUCCESS_VOID(rv);
2474 nsAutoString keyName;
2475 keyName.AppendLiteral(DEFAULT_BROWSER_AGENT_KEY_NAME);
2476 rv = regKey->Create(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER, keyName,
2477 nsIWindowsRegKey::ACCESS_WRITE);
2478 NS_ENSURE_SUCCESS_VOID(rv);
2480 FILETIME fileTime;
2481 GetSystemTimeAsFileTime(&fileTime);
2483 ULARGE_INTEGER integerTime;
2484 integerTime.u.LowPart = fileTime.dwLowDateTime;
2485 integerTime.u.HighPart = fileTime.dwHighDateTime;
2487 rv = regKey->WriteInt64Value(valueName, integerTime.QuadPart);
2488 NS_ENSURE_SUCCESS_VOID(rv);
2491 # endif // defined(MOZ_DEFAULT_BROWSER_AGENT)
2493 #endif // XP_WIN
2495 void UnlockProfile() {
2496 if (gProfileLock) {
2497 gProfileLock->Unlock();
2501 nsresult LaunchChild(bool aBlankCommandLine, bool aTryExec) {
2502 // Restart this process by exec'ing it into the current process
2503 // if supported by the platform. Otherwise, use NSPR.
2505 #ifdef MOZ_JPROF
2506 // make sure JPROF doesn't think we're E10s
2507 unsetenv("JPROF_ISCHILD");
2508 #endif
2510 if (aBlankCommandLine) {
2511 gRestartArgc = 1;
2512 gRestartArgv[gRestartArgc] = nullptr;
2515 #if defined(MOZ_HAS_REMOTE)
2516 if (gRestartWithoutRemote) {
2517 SaveToEnv("MOZ_NO_REMOTE=1");
2519 #endif
2521 SaveToEnv("MOZ_LAUNCHED_CHILD=1");
2522 #if defined(MOZ_LAUNCHER_PROCESS)
2523 SaveToEnv("MOZ_LAUNCHER_PROCESS=1");
2524 #endif // defined(MOZ_LAUNCHER_PROCESS)
2526 #if !defined(MOZ_WIDGET_ANDROID) // Android has separate restart code.
2527 # if defined(XP_MACOSX)
2528 InitializeMacApp();
2529 CommandLineServiceMac::SetupMacCommandLine(gRestartArgc, gRestartArgv, true);
2530 LaunchChildMac(gRestartArgc, gRestartArgv);
2531 # else
2532 nsCOMPtr<nsIFile> lf;
2533 nsresult rv = XRE_GetBinaryPath(getter_AddRefs(lf));
2534 if (NS_FAILED(rv)) return rv;
2536 # if defined(XP_WIN)
2537 nsAutoString exePath;
2538 rv = lf->GetPath(exePath);
2539 if (NS_FAILED(rv)) return rv;
2541 HANDLE hProcess;
2542 if (!WinLaunchChild(exePath.get(), gRestartArgc, gRestartArgv, nullptr,
2543 &hProcess))
2544 return NS_ERROR_FAILURE;
2545 // Keep the current process around until the restarted process has created
2546 // its message queue, to avoid the launched process's windows being forced
2547 // into the background.
2548 mozilla::WaitForInputIdle(hProcess);
2549 ::CloseHandle(hProcess);
2551 # else
2552 nsAutoCString exePath;
2553 rv = lf->GetNativePath(exePath);
2554 if (NS_FAILED(rv)) return rv;
2556 # if defined(XP_UNIX)
2557 if (aTryExec) {
2558 execv(exePath.get(), gRestartArgv);
2560 // If execv returns we know it's because it failed.
2561 return NS_ERROR_FAILURE;
2563 # endif
2564 if (PR_CreateProcessDetached(exePath.get(), gRestartArgv, nullptr, nullptr) ==
2565 PR_FAILURE) {
2566 return NS_ERROR_FAILURE;
2569 // Note that we don't know if the child process starts okay, if it
2570 // immediately returns non-zero then we may mask that by returning a zero
2571 // exit status.
2573 # endif // WP_WIN
2574 # endif // WP_MACOSX
2575 #endif // MOZ_WIDGET_ANDROID
2577 return NS_ERROR_LAUNCHED_CHILD_PROCESS;
2580 static const char kProfileProperties[] =
2581 "chrome://mozapps/locale/profile/profileSelection.properties";
2583 namespace {
2586 * This class, instead of a raw nsresult, should be the return type of any
2587 * function called by SelectProfile that initializes XPCOM.
2589 class ReturnAbortOnError {
2590 public:
2591 MOZ_IMPLICIT ReturnAbortOnError(nsresult aRv) { mRv = ConvertRv(aRv); }
2593 operator nsresult() { return mRv; }
2595 private:
2596 inline nsresult ConvertRv(nsresult aRv) {
2597 if (NS_SUCCEEDED(aRv) || aRv == NS_ERROR_LAUNCHED_CHILD_PROCESS) {
2598 return aRv;
2600 #ifdef MOZ_BACKGROUNDTASKS
2601 // A background task that fails to lock its profile will return
2602 // NS_ERROR_UNEXPECTED and this will allow the task to exit with a
2603 // non-zero exit code.
2604 if (aRv == NS_ERROR_UNEXPECTED && BackgroundTasks::IsBackgroundTaskMode()) {
2605 return aRv;
2607 #endif
2608 return NS_ERROR_ABORT;
2611 nsresult mRv;
2614 } // namespace
2616 static nsresult ProfileMissingDialog(nsINativeAppSupport* aNative) {
2617 #ifdef MOZ_WIDGET_ANDROID
2618 // We cannot really do anything this early during initialization, so we just
2619 // return as this is likely the effect of misconfiguration on the test side.
2620 // Non-test code paths cannot set the profile folder, which is always the
2621 // default one.
2622 Output(true, "Could not find profile folder.\n");
2623 return NS_ERROR_ABORT;
2624 #else
2625 # ifdef MOZ_BACKGROUNDTASKS
2626 if (BackgroundTasks::IsBackgroundTaskMode()) {
2627 // We should never get to this point in background task mode.
2628 Output(false,
2629 "Could not determine any profile running in backgroundtask mode!\n");
2630 return NS_ERROR_ABORT;
2632 # endif // MOZ_BACKGROUNDTASKS
2634 nsresult rv;
2636 ScopedXPCOMStartup xpcom;
2637 rv = xpcom.Initialize();
2638 NS_ENSURE_SUCCESS(rv, rv);
2640 rv = xpcom.SetWindowCreator(aNative);
2641 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
2643 { // extra scoping is needed so we release these components before xpcom
2644 // shutdown
2645 nsCOMPtr<nsIStringBundleService> sbs =
2646 mozilla::components::StringBundle::Service();
2647 NS_ENSURE_TRUE(sbs, NS_ERROR_FAILURE);
2649 nsCOMPtr<nsIStringBundle> sb;
2650 sbs->CreateBundle(kProfileProperties, getter_AddRefs(sb));
2651 NS_ENSURE_TRUE_LOG(sbs, NS_ERROR_FAILURE);
2653 NS_ConvertUTF8toUTF16 appName(gAppData->name);
2654 AutoTArray<nsString, 2> params = {appName, appName};
2656 // profileMissing
2657 nsAutoString missingMessage;
2658 rv = sb->FormatStringFromName("profileMissing", params, missingMessage);
2659 NS_ENSURE_SUCCESS(rv, NS_ERROR_ABORT);
2661 nsAutoString missingTitle;
2662 params.SetLength(1);
2663 rv = sb->FormatStringFromName("profileMissingTitle", params, missingTitle);
2664 NS_ENSURE_SUCCESS(rv, NS_ERROR_ABORT);
2666 nsCOMPtr<nsIPromptService> ps(do_GetService(NS_PROMPTSERVICE_CONTRACTID));
2667 NS_ENSURE_TRUE(ps, NS_ERROR_FAILURE);
2669 ps->Alert(nullptr, missingTitle.get(), missingMessage.get());
2671 return NS_ERROR_ABORT;
2673 #endif // MOZ_WIDGET_ANDROID
2676 static ReturnAbortOnError ProfileLockedDialog(nsIFile* aProfileDir,
2677 nsIFile* aProfileLocalDir,
2678 nsIProfileUnlocker* aUnlocker,
2679 nsINativeAppSupport* aNative,
2680 nsIProfileLock** aResult) {
2681 nsresult rv;
2683 bool exists;
2684 aProfileDir->Exists(&exists);
2685 if (!exists) {
2686 return ProfileMissingDialog(aNative);
2689 ScopedXPCOMStartup xpcom;
2690 rv = xpcom.Initialize();
2691 NS_ENSURE_SUCCESS(rv, rv);
2693 #if defined(MOZ_TELEMETRY_REPORTING)
2694 // We cannot check if telemetry has been disabled by the user, yet.
2695 // So, rely on the build time settings, instead.
2696 mozilla::Telemetry::WriteFailedProfileLock(aProfileDir);
2697 #endif
2699 rv = xpcom.SetWindowCreator(aNative);
2700 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
2702 { // extra scoping is needed so we release these components before xpcom
2703 // shutdown
2704 nsCOMPtr<nsIStringBundleService> sbs =
2705 mozilla::components::StringBundle::Service();
2706 NS_ENSURE_TRUE(sbs, NS_ERROR_FAILURE);
2708 nsCOMPtr<nsIStringBundle> sb;
2709 sbs->CreateBundle(kProfileProperties, getter_AddRefs(sb));
2710 NS_ENSURE_TRUE_LOG(sbs, NS_ERROR_FAILURE);
2712 NS_ConvertUTF8toUTF16 appName(gAppData->name);
2713 AutoTArray<nsString, 3> params = {appName, appName, appName};
2715 nsAutoString killMessage;
2716 #ifndef XP_MACOSX
2717 rv = sb->FormatStringFromName(
2718 aUnlocker ? "restartMessageUnlocker" : "restartMessageNoUnlocker2",
2719 params, killMessage);
2720 #else
2721 rv = sb->FormatStringFromName(
2722 aUnlocker ? "restartMessageUnlockerMac" : "restartMessageNoUnlockerMac",
2723 params, killMessage);
2724 #endif
2725 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
2727 params.SetLength(1);
2728 nsAutoString killTitle;
2729 rv = sb->FormatStringFromName("restartTitle", params, killTitle);
2730 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
2732 #ifdef MOZ_BACKGROUNDTASKS
2733 if (BackgroundTasks::IsBackgroundTaskMode()) {
2734 // This error is handled specially to exit with a non-zero exit code.
2735 printf_stderr("%s\n", NS_LossyConvertUTF16toASCII(killMessage).get());
2736 return NS_ERROR_UNEXPECTED;
2738 #endif
2740 if (gfxPlatform::IsHeadless()) {
2741 // TODO: make a way to turn off all dialogs when headless.
2742 Output(true, "%s\n", NS_LossyConvertUTF16toASCII(killMessage).get());
2743 return NS_ERROR_FAILURE;
2746 nsCOMPtr<nsIPromptService> ps(do_GetService(NS_PROMPTSERVICE_CONTRACTID));
2747 NS_ENSURE_TRUE(ps, NS_ERROR_FAILURE);
2749 if (aUnlocker) {
2750 int32_t button;
2751 #ifdef MOZ_WIDGET_ANDROID
2752 // On Android we always kill the process if the lock is still being held
2753 button = 0;
2754 #else
2755 const uint32_t flags = (nsIPromptService::BUTTON_TITLE_IS_STRING *
2756 nsIPromptService::BUTTON_POS_0) +
2757 (nsIPromptService::BUTTON_TITLE_CANCEL *
2758 nsIPromptService::BUTTON_POS_1);
2760 bool checkState = false;
2761 rv = ps->ConfirmEx(nullptr, killTitle.get(), killMessage.get(), flags,
2762 killTitle.get(), nullptr, nullptr, nullptr,
2763 &checkState, &button);
2764 NS_ENSURE_SUCCESS_LOG(rv, rv);
2765 #endif
2767 if (button == 0) {
2768 rv = aUnlocker->Unlock(nsIProfileUnlocker::FORCE_QUIT);
2769 if (NS_FAILED(rv)) {
2770 return rv;
2773 SaveFileToEnv("XRE_PROFILE_PATH", aProfileDir);
2774 SaveFileToEnv("XRE_PROFILE_LOCAL_PATH", aProfileLocalDir);
2776 #if defined(MOZ_HAS_REMOTE)
2777 if (gRemoteService) {
2778 gRemoteService->UnlockStartup();
2779 gRemoteService = nullptr;
2781 #endif
2782 return LaunchChild(false, true);
2784 } else {
2785 rv = ps->Alert(nullptr, killTitle.get(), killMessage.get());
2786 NS_ENSURE_SUCCESS_LOG(rv, rv);
2789 return NS_ERROR_ABORT;
2793 static const char kProfileManagerURL[] =
2794 "chrome://mozapps/content/profile/profileSelection.xhtml";
2796 static ReturnAbortOnError ShowProfileManager(
2797 nsIToolkitProfileService* aProfileSvc, nsINativeAppSupport* aNative) {
2798 nsresult rv;
2800 nsCOMPtr<nsIFile> profD, profLD;
2801 bool offline = false;
2802 int32_t dialogReturn;
2805 ScopedXPCOMStartup xpcom;
2806 rv = xpcom.Initialize();
2807 NS_ENSURE_SUCCESS(rv, rv);
2809 rv = xpcom.SetWindowCreator(aNative);
2810 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
2812 #ifdef XP_MACOSX
2813 InitializeMacApp();
2814 CommandLineServiceMac::SetupMacCommandLine(gRestartArgc, gRestartArgv,
2815 true);
2816 #endif
2818 { // extra scoping is needed so we release these components before xpcom
2819 // shutdown
2820 nsCOMPtr<nsIWindowWatcher> windowWatcher(
2821 do_GetService(NS_WINDOWWATCHER_CONTRACTID));
2822 nsCOMPtr<nsIDialogParamBlock> ioParamBlock(
2823 do_CreateInstance(NS_DIALOGPARAMBLOCK_CONTRACTID));
2824 nsCOMPtr<nsIMutableArray> dlgArray(
2825 do_CreateInstance(NS_ARRAY_CONTRACTID));
2826 NS_ENSURE_TRUE(windowWatcher && ioParamBlock && dlgArray,
2827 NS_ERROR_FAILURE);
2829 ioParamBlock->SetObjects(dlgArray);
2831 nsCOMPtr<nsIAppStartup> appStartup(components::AppStartup::Service());
2832 NS_ENSURE_TRUE(appStartup, NS_ERROR_FAILURE);
2834 nsAutoCString features("centerscreen,chrome,modal,titlebar");
2835 // If we're launching a private browsing window make sure to set that
2836 // feature for the Profile Manager window as well, so it groups correctly
2837 // on the Windows taskbar.
2838 if (CheckArgExists("private-window") == ARG_FOUND) {
2839 features.AppendLiteral(",private");
2841 nsCOMPtr<mozIDOMWindowProxy> newWindow;
2842 rv = windowWatcher->OpenWindow(
2843 nullptr, nsDependentCString(kProfileManagerURL), "_blank"_ns,
2844 features, ioParamBlock, getter_AddRefs(newWindow));
2846 NS_ENSURE_SUCCESS_LOG(rv, rv);
2848 rv = ioParamBlock->GetInt(0, &dialogReturn);
2849 if (NS_FAILED(rv) || dialogReturn == nsIToolkitProfileService::exit) {
2850 return NS_ERROR_ABORT;
2853 int32_t startOffline;
2854 rv = ioParamBlock->GetInt(1, &startOffline);
2855 offline = NS_SUCCEEDED(rv) && startOffline == 1;
2857 rv = dlgArray->QueryElementAt(0, NS_GET_IID(nsIFile),
2858 getter_AddRefs(profD));
2859 NS_ENSURE_SUCCESS_LOG(rv, rv);
2861 rv = dlgArray->QueryElementAt(1, NS_GET_IID(nsIFile),
2862 getter_AddRefs(profLD));
2863 NS_ENSURE_SUCCESS_LOG(rv, rv);
2867 if (offline) {
2868 SaveToEnv("XRE_START_OFFLINE=1");
2871 // User requested that we restart back into the profile manager.
2872 if (dialogReturn == nsIToolkitProfileService::restart) {
2873 SaveToEnv("XRE_RESTART_TO_PROFILE_MANAGER=1");
2874 SaveToEnv("XRE_RESTARTED_BY_PROFILE_MANAGER=1");
2875 } else {
2876 MOZ_ASSERT(dialogReturn == nsIToolkitProfileService::launchWithProfile);
2877 SaveFileToEnv("XRE_PROFILE_PATH", profD);
2878 SaveFileToEnv("XRE_PROFILE_LOCAL_PATH", profLD);
2879 SaveToEnv("XRE_RESTARTED_BY_PROFILE_MANAGER=1");
2882 if (gRestartedByOS) {
2883 // Re-add this argument when actually starting the application.
2884 char** newArgv =
2885 (char**)realloc(gRestartArgv, sizeof(char*) * (gRestartArgc + 2));
2886 NS_ENSURE_TRUE(newArgv, NS_ERROR_OUT_OF_MEMORY);
2887 gRestartArgv = newArgv;
2888 gRestartArgv[gRestartArgc++] = const_cast<char*>("-os-restarted");
2889 gRestartArgv[gRestartArgc] = nullptr;
2891 #if defined(MOZ_HAS_REMOTE)
2892 if (gRemoteService) {
2893 gRemoteService->UnlockStartup();
2894 gRemoteService = nullptr;
2896 #endif
2897 return LaunchChild(false, true);
2900 static bool gDoMigration = false;
2901 static bool gDoProfileReset = false;
2902 static nsCOMPtr<nsIToolkitProfile> gResetOldProfile;
2904 static nsresult LockProfile(nsINativeAppSupport* aNative, nsIFile* aRootDir,
2905 nsIFile* aLocalDir, nsIToolkitProfile* aProfile,
2906 nsIProfileLock** aResult) {
2907 // If you close Firefox and very quickly reopen it, the old Firefox may
2908 // still be closing down. Rather than immediately showing the
2909 // "Firefox is running but is not responding" message, we spend a few
2910 // seconds retrying first.
2912 static const int kLockRetrySeconds = 5;
2913 static const int kLockRetrySleepMS = 100;
2915 nsresult rv;
2916 nsCOMPtr<nsIProfileUnlocker> unlocker;
2917 const TimeStamp start = TimeStamp::Now();
2918 do {
2919 if (aProfile) {
2920 rv = aProfile->Lock(getter_AddRefs(unlocker), aResult);
2921 } else {
2922 rv = NS_LockProfilePath(aRootDir, aLocalDir, getter_AddRefs(unlocker),
2923 aResult);
2925 if (NS_SUCCEEDED(rv)) {
2926 StartupTimeline::Record(StartupTimeline::AFTER_PROFILE_LOCKED);
2927 return NS_OK;
2929 PR_Sleep(kLockRetrySleepMS);
2930 } while (TimeStamp::Now() - start <
2931 TimeDuration::FromSeconds(kLockRetrySeconds));
2933 return ProfileLockedDialog(aRootDir, aLocalDir, unlocker, aNative, aResult);
2936 // Pick a profile. We need to end up with a profile root dir, local dir and
2937 // potentially an nsIToolkitProfile instance.
2939 // 1) check for --profile <path>
2940 // 2) check for -P <name>
2941 // 3) check for --ProfileManager
2942 // 4) use the default profile, if there is one
2943 // 5) if there are *no* profiles, set up profile-migration
2944 // 6) display the profile-manager UI
2945 static nsresult SelectProfile(nsToolkitProfileService* aProfileSvc,
2946 nsINativeAppSupport* aNative, nsIFile** aRootDir,
2947 nsIFile** aLocalDir, nsIToolkitProfile** aProfile,
2948 bool* aWasDefaultSelection) {
2949 StartupTimeline::Record(StartupTimeline::SELECT_PROFILE);
2951 nsresult rv;
2953 if (EnvHasValue("MOZ_RESET_PROFILE_RESTART")) {
2954 gDoProfileReset = true;
2955 gDoMigration = true;
2958 // reset-profile and migration args need to be checked before any profiles are
2959 // chosen below.
2960 ArgResult ar = CheckArg("reset-profile");
2961 if (ar == ARG_FOUND) {
2962 gDoProfileReset = true;
2965 ar = CheckArg("migration");
2966 if (ar == ARG_FOUND) {
2967 gDoMigration = true;
2970 #if defined(XP_WIN)
2971 // This arg is only used to indicate to telemetry that a profile refresh
2972 // (reset+migration) was requested from the uninstaller, pass this along
2973 // via an environment variable for simplicity.
2974 ar = CheckArg("uninstaller-profile-refresh");
2975 if (ar == ARG_FOUND) {
2976 SaveToEnv("MOZ_UNINSTALLER_PROFILE_REFRESH=1");
2978 #endif
2980 if (EnvHasValue("XRE_RESTART_TO_PROFILE_MANAGER")) {
2981 return ShowProfileManager(aProfileSvc, aNative);
2984 // Ask the profile manager to select the profile directories to use.
2985 bool didCreate = false;
2986 rv = aProfileSvc->SelectStartupProfile(&gArgc, gArgv, gDoProfileReset,
2987 aRootDir, aLocalDir, aProfile,
2988 &didCreate, aWasDefaultSelection);
2990 if (rv == NS_ERROR_SHOW_PROFILE_MANAGER) {
2991 return ShowProfileManager(aProfileSvc, aNative);
2994 NS_ENSURE_SUCCESS(rv, rv);
2996 if (didCreate) {
2997 // For a fresh install, we would like to let users decide
2998 // to do profile migration on their own later after using.
2999 gDoProfileReset = false;
3000 gDoMigration = false;
3003 if (gDoProfileReset && !*aProfile) {
3004 NS_WARNING("Profile reset is only supported for named profiles.");
3005 return NS_ERROR_ABORT;
3008 // No profile could be found. This generally shouldn't happen, a new profile
3009 // should be created in all cases except for profile reset which is covered
3010 // above, but just in case...
3011 if (!*aRootDir) {
3012 NS_WARNING("Failed to select or create profile.");
3013 return NS_ERROR_ABORT;
3016 return NS_OK;
3019 #ifdef MOZ_BLOCK_PROFILE_DOWNGRADE
3020 struct FileWriteFunc final : public JSONWriteFunc {
3021 FILE* mFile;
3022 explicit FileWriteFunc(FILE* aFile) : mFile(aFile) {}
3024 void Write(const Span<const char>& aStr) final {
3025 fprintf(mFile, "%.*s", int(aStr.size()), aStr.data());
3029 static void SubmitDowngradeTelemetry(const nsCString& aLastVersion,
3030 bool aHasSync, int32_t aButton) {
3031 nsCOMPtr<nsIPrefService> prefSvc =
3032 do_GetService("@mozilla.org/preferences-service;1");
3033 NS_ENSURE_TRUE_VOID(prefSvc);
3035 nsCOMPtr<nsIPrefBranch> prefBranch = do_QueryInterface(prefSvc);
3036 NS_ENSURE_TRUE_VOID(prefBranch);
3038 bool enabled;
3039 nsresult rv =
3040 prefBranch->GetBoolPref(kPrefHealthReportUploadEnabled, &enabled);
3041 NS_ENSURE_SUCCESS_VOID(rv);
3042 if (!enabled) {
3043 return;
3046 nsCString server;
3047 rv = prefBranch->GetCharPref("toolkit.telemetry.server", server);
3048 NS_ENSURE_SUCCESS_VOID(rv);
3050 nsCString clientId;
3051 rv = prefBranch->GetCharPref("toolkit.telemetry.cachedClientID", clientId);
3052 NS_ENSURE_SUCCESS_VOID(rv);
3054 rv = prefSvc->GetDefaultBranch(nullptr, getter_AddRefs(prefBranch));
3055 NS_ENSURE_SUCCESS_VOID(rv);
3057 nsCString channel("default");
3058 rv = prefBranch->GetCharPref("app.update.channel", channel);
3059 NS_ENSURE_SUCCESS_VOID(rv);
3061 nsID uuid;
3062 rv = nsID::GenerateUUIDInPlace(uuid);
3063 NS_ENSURE_SUCCESS_VOID(rv);
3065 nsCString arch("null");
3066 nsCOMPtr<nsIPropertyBag2> sysInfo =
3067 do_GetService("@mozilla.org/system-info;1");
3068 NS_ENSURE_TRUE_VOID(sysInfo);
3069 sysInfo->GetPropertyAsACString(u"arch"_ns, arch);
3071 time_t now;
3072 time(&now);
3073 char date[sizeof "YYYY-MM-DDThh:mm:ss.000Z"];
3074 strftime(date, sizeof date, "%FT%T.000Z", gmtime(&now));
3076 NSID_TrimBracketsASCII pingId(uuid);
3077 constexpr auto pingType = "downgrade"_ns;
3079 int32_t pos = aLastVersion.Find("_");
3080 if (pos == kNotFound) {
3081 return;
3084 const nsDependentCSubstring lastVersion = Substring(aLastVersion, 0, pos);
3085 const nsDependentCSubstring lastBuildId =
3086 Substring(aLastVersion, pos + 1, 14);
3088 nsPrintfCString url("%s/submit/telemetry/%s/%s/%s/%s/%s/%s?v=%d",
3089 server.get(), PromiseFlatCString(pingId).get(),
3090 pingType.get(), (const char*)gAppData->name,
3091 (const char*)gAppData->version, channel.get(),
3092 (const char*)gAppData->buildID,
3093 TELEMETRY_PING_FORMAT_VERSION);
3095 nsCOMPtr<nsIFile> pingFile;
3096 rv = NS_GetSpecialDirectory(XRE_USER_APP_DATA_DIR, getter_AddRefs(pingFile));
3097 NS_ENSURE_SUCCESS_VOID(rv);
3098 rv = pingFile->Append(u"Pending Pings"_ns);
3099 NS_ENSURE_SUCCESS_VOID(rv);
3100 rv = pingFile->Create(nsIFile::DIRECTORY_TYPE, 0755);
3101 if (NS_FAILED(rv) && rv != NS_ERROR_FILE_ALREADY_EXISTS) {
3102 return;
3104 rv = pingFile->Append(NS_ConvertUTF8toUTF16(pingId));
3105 NS_ENSURE_SUCCESS_VOID(rv);
3107 nsCOMPtr<nsIFile> pingSender;
3108 rv = NS_GetSpecialDirectory(NS_GRE_BIN_DIR, getter_AddRefs(pingSender));
3109 NS_ENSURE_SUCCESS_VOID(rv);
3110 # ifdef XP_WIN
3111 pingSender->Append(u"pingsender.exe"_ns);
3112 # else
3113 pingSender->Append(u"pingsender"_ns);
3114 # endif
3116 bool exists;
3117 rv = pingSender->Exists(&exists);
3118 NS_ENSURE_SUCCESS_VOID(rv);
3119 if (!exists) {
3120 return;
3123 FILE* file;
3124 rv = pingFile->OpenANSIFileDesc("w", &file);
3125 NS_ENSURE_SUCCESS_VOID(rv);
3127 JSONWriter w(MakeUnique<FileWriteFunc>(file));
3128 w.Start();
3130 w.StringProperty("type",
3131 Span<const char>(pingType.Data(), pingType.Length()));
3132 w.StringProperty("id", PromiseFlatCString(pingId));
3133 w.StringProperty("creationDate", MakeStringSpan(date));
3134 w.IntProperty("version", TELEMETRY_PING_FORMAT_VERSION);
3135 w.StringProperty("clientId", clientId);
3136 w.StartObjectProperty("application");
3138 w.StringProperty("architecture", arch);
3139 w.StringProperty(
3140 "buildId",
3141 MakeStringSpan(static_cast<const char*>(gAppData->buildID)));
3142 w.StringProperty(
3143 "name", MakeStringSpan(static_cast<const char*>(gAppData->name)));
3144 w.StringProperty(
3145 "version",
3146 MakeStringSpan(static_cast<const char*>(gAppData->version)));
3147 w.StringProperty("displayVersion",
3148 MOZ_STRINGIFY(MOZ_APP_VERSION_DISPLAY));
3149 w.StringProperty(
3150 "vendor", MakeStringSpan(static_cast<const char*>(gAppData->vendor)));
3151 w.StringProperty("platformVersion", gToolkitVersion);
3152 # ifdef TARGET_XPCOM_ABI
3153 w.StringProperty("xpcomAbi", TARGET_XPCOM_ABI);
3154 # else
3155 w.StringProperty("xpcomAbi", "unknown");
3156 # endif
3157 w.StringProperty("channel", channel);
3159 w.EndObject();
3160 w.StartObjectProperty("payload");
3162 w.StringProperty("lastVersion", PromiseFlatCString(lastVersion));
3163 w.StringProperty("lastBuildId", PromiseFlatCString(lastBuildId));
3164 w.BoolProperty("hasSync", aHasSync);
3165 w.IntProperty("button", aButton);
3167 w.EndObject();
3169 w.End();
3171 fclose(file);
3173 PathString filePath = pingFile->NativePath();
3174 const filesystem::Path::value_type* args[2];
3175 # ifdef XP_WIN
3176 nsString urlw = NS_ConvertUTF8toUTF16(url);
3177 args[0] = urlw.get();
3178 # else
3179 args[0] = url.get();
3180 # endif
3181 args[1] = filePath.get();
3183 nsCOMPtr<nsIProcess> process =
3184 do_CreateInstance("@mozilla.org/process/util;1");
3185 NS_ENSURE_TRUE_VOID(process);
3186 process->Init(pingSender);
3187 process->SetStartHidden(true);
3188 process->SetNoShell(true);
3190 # ifdef XP_WIN
3191 process->Runw(false, args, 2);
3192 # else
3193 process->Run(false, args, 2);
3194 # endif
3197 static const char kProfileDowngradeURL[] =
3198 "chrome://mozapps/content/profile/profileDowngrade.xhtml";
3200 static ReturnAbortOnError CheckDowngrade(nsIFile* aProfileDir,
3201 nsINativeAppSupport* aNative,
3202 nsIToolkitProfileService* aProfileSvc,
3203 const nsCString& aLastVersion) {
3204 int32_t result = 0;
3205 nsresult rv;
3208 if (gfxPlatform::IsHeadless()) {
3209 // TODO: make a way to turn off all dialogs when headless.
3210 Output(true,
3211 "This profile was last used with a newer version of this "
3212 "application. Please create a new profile.\n");
3213 return NS_ERROR_ABORT;
3216 ScopedXPCOMStartup xpcom;
3217 rv = xpcom.Initialize();
3218 NS_ENSURE_SUCCESS(rv, rv);
3220 rv = xpcom.SetWindowCreator(aNative);
3221 NS_ENSURE_SUCCESS(rv, rv);
3223 { // extra scoping is needed so we release these components before xpcom
3224 // shutdown
3225 bool hasSync = false;
3226 nsCOMPtr<nsIPrefService> prefSvc =
3227 do_GetService("@mozilla.org/preferences-service;1");
3228 NS_ENSURE_TRUE(prefSvc, rv);
3230 nsCOMPtr<nsIFile> prefsFile;
3231 rv = aProfileDir->Clone(getter_AddRefs(prefsFile));
3232 NS_ENSURE_SUCCESS(rv, rv);
3234 rv = prefsFile->Append(u"prefs.js"_ns);
3235 NS_ENSURE_SUCCESS(rv, rv);
3237 rv = prefSvc->ReadUserPrefsFromFile(prefsFile);
3238 if (NS_SUCCEEDED(rv)) {
3239 nsCOMPtr<nsIPrefBranch> prefBranch = do_QueryInterface(prefSvc);
3241 rv = prefBranch->PrefHasUserValue("services.sync.username", &hasSync);
3242 NS_ENSURE_SUCCESS(rv, rv);
3245 nsCOMPtr<nsIWindowWatcher> windowWatcher =
3246 do_GetService(NS_WINDOWWATCHER_CONTRACTID);
3247 NS_ENSURE_TRUE(windowWatcher, NS_ERROR_ABORT);
3249 nsCOMPtr<nsIAppStartup> appStartup(components::AppStartup::Service());
3250 NS_ENSURE_TRUE(appStartup, NS_ERROR_FAILURE);
3252 nsCOMPtr<nsIDialogParamBlock> paramBlock =
3253 do_CreateInstance(NS_DIALOGPARAMBLOCK_CONTRACTID);
3254 NS_ENSURE_TRUE(paramBlock, NS_ERROR_ABORT);
3256 uint8_t flags = 0;
3257 if (hasSync) {
3258 flags |= nsIToolkitProfileService::hasSync;
3261 paramBlock->SetInt(0, flags);
3263 nsAutoCString features("centerscreen,chrome,modal,titlebar");
3264 // If we're launching a private browsing window make sure to set that
3265 // feature for the Profile Manager window as well, so it groups correctly
3266 // on the Windows taskbar.
3267 if (CheckArgExists("private-window") == ARG_FOUND) {
3268 features.AppendLiteral(",private");
3270 nsCOMPtr<mozIDOMWindowProxy> newWindow;
3271 rv = windowWatcher->OpenWindow(
3272 nullptr, nsDependentCString(kProfileDowngradeURL), "_blank"_ns,
3273 features, paramBlock, getter_AddRefs(newWindow));
3274 NS_ENSURE_SUCCESS(rv, rv);
3276 paramBlock->GetInt(1, &result);
3278 SubmitDowngradeTelemetry(aLastVersion, hasSync, result);
3282 if (result == nsIToolkitProfileService::createNewProfile) {
3283 // Create a new profile and start it.
3284 nsCString profileName;
3285 profileName.AssignLiteral("default");
3286 # ifdef MOZ_DEDICATED_PROFILES
3287 profileName.Append("-" MOZ_STRINGIFY(MOZ_UPDATE_CHANNEL));
3288 # endif
3289 nsCOMPtr<nsIToolkitProfile> newProfile;
3290 rv = aProfileSvc->CreateUniqueProfile(nullptr, profileName,
3291 getter_AddRefs(newProfile));
3292 NS_ENSURE_SUCCESS(rv, rv);
3293 rv = aProfileSvc->SetDefaultProfile(newProfile);
3294 NS_ENSURE_SUCCESS(rv, rv);
3295 rv = aProfileSvc->Flush();
3296 NS_ENSURE_SUCCESS(rv, rv);
3298 nsCOMPtr<nsIFile> profD, profLD;
3299 rv = newProfile->GetRootDir(getter_AddRefs(profD));
3300 NS_ENSURE_SUCCESS(rv, rv);
3301 rv = newProfile->GetLocalDir(getter_AddRefs(profLD));
3302 NS_ENSURE_SUCCESS(rv, rv);
3304 SaveFileToEnv("XRE_PROFILE_PATH", profD);
3305 SaveFileToEnv("XRE_PROFILE_LOCAL_PATH", profLD);
3307 return LaunchChild(false, true);
3310 // Cancel
3311 return NS_ERROR_ABORT;
3313 #endif
3316 * Extracts the various parts of a compatibility version string.
3318 * Compatibility versions are of the form
3319 * "<appversion>_<appbuildid>/<platformbuildid>". The toolkit version comparator
3320 * can only handle 32-bit numbers and in the normal case build IDs are larger
3321 * than this. So if the build ID is numeric we split it into two version parts.
3323 static void ExtractCompatVersionInfo(const nsACString& aCompatVersion,
3324 nsACString& aAppVersion,
3325 nsACString& aAppBuildID) {
3326 int32_t underscorePos = aCompatVersion.FindChar('_');
3327 int32_t slashPos = aCompatVersion.FindChar('/');
3329 if (underscorePos == kNotFound || slashPos == kNotFound ||
3330 slashPos < underscorePos) {
3331 NS_WARNING(
3332 "compatibility.ini Version string does not match the expected format.");
3334 // Fall back to just using the entire string as the version.
3335 aAppVersion = aCompatVersion;
3336 aAppBuildID.Truncate(0);
3337 return;
3340 aAppVersion = Substring(aCompatVersion, 0, underscorePos);
3341 aAppBuildID = Substring(aCompatVersion, underscorePos + 1,
3342 slashPos - (underscorePos + 1));
3346 * Compares the provided compatibility versions. Returns 0 if they match,
3347 * < 0 if the new version is considered an upgrade from the old version and
3348 * > 0 if the new version is considered a downgrade from the old version.
3350 int32_t CompareCompatVersions(const nsACString& aOldCompatVersion,
3351 const nsACString& aNewCompatVersion) {
3352 // Hardcode the case where the last run was in safe mode (Bug 1556612). We
3353 // cannot tell if this is a downgrade or not so just assume it isn't and let
3354 // the user proceed.
3355 if (aOldCompatVersion.EqualsLiteral("Safe Mode")) {
3356 return -1;
3359 // Extract the major version part from the version string and only use that
3360 // for version comparison.
3361 int32_t index = aOldCompatVersion.FindChar('.');
3362 const nsACString& oldMajorVersion = Substring(
3363 aOldCompatVersion, 0, index < 0 ? aOldCompatVersion.Length() : index);
3364 index = aNewCompatVersion.FindChar('.');
3365 const nsACString& newMajorVersion = Substring(
3366 aNewCompatVersion, 0, index < 0 ? aNewCompatVersion.Length() : index);
3368 return CompareVersions(PromiseFlatCString(oldMajorVersion).get(),
3369 PromiseFlatCString(newMajorVersion).get());
3373 * Checks the compatibility.ini file to see if we have updated our application
3374 * or otherwise invalidated our caches. If the application has been updated,
3375 * we return false; otherwise, we return true.
3377 * We also write the status of the caches (valid/invalid) into the return param
3378 * aCachesOK. The aCachesOK is always invalid if the application has been
3379 * updated.
3381 * Finally, aIsDowngrade is set to true if the current application is older
3382 * than that previously used by the profile.
3384 static bool CheckCompatibility(nsIFile* aProfileDir, const nsCString& aVersion,
3385 const nsCString& aOSABI, nsIFile* aXULRunnerDir,
3386 nsIFile* aAppDir, nsIFile* aFlagFile,
3387 bool* aCachesOK, bool* aIsDowngrade,
3388 nsCString& aLastVersion) {
3389 *aCachesOK = false;
3390 *aIsDowngrade = false;
3391 gLastAppVersion.SetIsVoid(true);
3392 gLastAppBuildID.SetIsVoid(true);
3394 nsCOMPtr<nsIFile> file;
3395 aProfileDir->Clone(getter_AddRefs(file));
3396 if (!file) return false;
3397 file->AppendNative(FILE_COMPATIBILITY_INFO);
3399 nsINIParser parser;
3400 nsresult rv = parser.Init(file);
3401 if (NS_FAILED(rv)) return false;
3403 rv = parser.GetString("Compatibility", "LastVersion", aLastVersion);
3404 if (NS_FAILED(rv)) {
3405 return false;
3408 if (!aLastVersion.Equals(aVersion)) {
3409 // The version is not the same. Whether it's a downgrade depends on an
3410 // actual comparison:
3411 *aIsDowngrade = 0 < CompareCompatVersions(aLastVersion, aVersion);
3412 ExtractCompatVersionInfo(aLastVersion, gLastAppVersion, gLastAppBuildID);
3413 return false;
3416 // If we get here, the version matched, but there may still be other
3417 // differences between us and the build that the profile last ran under.
3419 gLastAppVersion.Assign(gAppData->version);
3420 gLastAppBuildID.Assign(gAppData->buildID);
3422 nsAutoCString buf;
3423 rv = parser.GetString("Compatibility", "LastOSABI", buf);
3424 if (NS_FAILED(rv) || !aOSABI.Equals(buf)) return false;
3426 rv = parser.GetString("Compatibility", "LastPlatformDir", buf);
3427 if (NS_FAILED(rv)) return false;
3429 nsCOMPtr<nsIFile> lf;
3430 rv = NS_NewNativeLocalFile(""_ns, false, getter_AddRefs(lf));
3431 if (NS_FAILED(rv)) return false;
3433 rv = lf->SetPersistentDescriptor(buf);
3434 if (NS_FAILED(rv)) return false;
3436 bool eq;
3437 rv = lf->Equals(aXULRunnerDir, &eq);
3438 if (NS_FAILED(rv) || !eq) return false;
3440 if (aAppDir) {
3441 rv = parser.GetString("Compatibility", "LastAppDir", buf);
3442 if (NS_FAILED(rv)) return false;
3444 rv = NS_NewNativeLocalFile(""_ns, false, getter_AddRefs(lf));
3445 if (NS_FAILED(rv)) return false;
3447 rv = lf->SetPersistentDescriptor(buf);
3448 if (NS_FAILED(rv)) return false;
3450 rv = lf->Equals(aAppDir, &eq);
3451 if (NS_FAILED(rv) || !eq) return false;
3454 // If we see this flag, caches are invalid.
3455 rv = parser.GetString("Compatibility", "InvalidateCaches", buf);
3456 *aCachesOK = (NS_FAILED(rv) || !buf.EqualsLiteral("1"));
3458 bool purgeCaches = false;
3459 if (aFlagFile && NS_SUCCEEDED(aFlagFile->Exists(&purgeCaches)) &&
3460 purgeCaches) {
3461 *aCachesOK = false;
3464 return true;
3467 void BuildCompatVersion(const char* aAppVersion, const char* aAppBuildID,
3468 const char* aToolkitBuildID, nsACString& aBuf) {
3469 aBuf.Assign(aAppVersion);
3470 aBuf.Append('_');
3471 aBuf.Append(aAppBuildID);
3472 aBuf.Append('/');
3473 aBuf.Append(aToolkitBuildID);
3476 static void BuildVersion(nsCString& aBuf) {
3477 BuildCompatVersion(gAppData->version, gAppData->buildID, gToolkitBuildID,
3478 aBuf);
3481 static void WriteVersion(nsIFile* aProfileDir, const nsCString& aVersion,
3482 const nsCString& aOSABI, nsIFile* aXULRunnerDir,
3483 nsIFile* aAppDir, bool invalidateCache) {
3484 nsCOMPtr<nsIFile> file;
3485 aProfileDir->Clone(getter_AddRefs(file));
3486 if (!file) return;
3487 file->AppendNative(FILE_COMPATIBILITY_INFO);
3489 nsAutoCString platformDir;
3490 Unused << aXULRunnerDir->GetPersistentDescriptor(platformDir);
3492 nsAutoCString appDir;
3493 if (aAppDir) Unused << aAppDir->GetPersistentDescriptor(appDir);
3495 PRFileDesc* fd;
3496 nsresult rv = file->OpenNSPRFileDesc(PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE,
3497 0600, &fd);
3498 if (NS_FAILED(rv)) {
3499 NS_ERROR("could not create output stream");
3500 return;
3503 static const char kHeader[] = "[Compatibility]" NS_LINEBREAK "LastVersion=";
3505 PR_Write(fd, kHeader, sizeof(kHeader) - 1);
3506 PR_Write(fd, aVersion.get(), aVersion.Length());
3508 static const char kOSABIHeader[] = NS_LINEBREAK "LastOSABI=";
3509 PR_Write(fd, kOSABIHeader, sizeof(kOSABIHeader) - 1);
3510 PR_Write(fd, aOSABI.get(), aOSABI.Length());
3512 static const char kPlatformDirHeader[] = NS_LINEBREAK "LastPlatformDir=";
3514 PR_Write(fd, kPlatformDirHeader, sizeof(kPlatformDirHeader) - 1);
3515 PR_Write(fd, platformDir.get(), platformDir.Length());
3517 static const char kAppDirHeader[] = NS_LINEBREAK "LastAppDir=";
3518 if (aAppDir) {
3519 PR_Write(fd, kAppDirHeader, sizeof(kAppDirHeader) - 1);
3520 PR_Write(fd, appDir.get(), appDir.Length());
3523 static const char kInvalidationHeader[] = NS_LINEBREAK "InvalidateCaches=1";
3524 if (invalidateCache)
3525 PR_Write(fd, kInvalidationHeader, sizeof(kInvalidationHeader) - 1);
3527 static const char kNL[] = NS_LINEBREAK;
3528 PR_Write(fd, kNL, sizeof(kNL) - 1);
3530 PR_Close(fd);
3534 * Returns true if the startup cache file was successfully removed.
3535 * Returns false if file->Clone fails at any point (OOM) or if unable
3536 * to remove the startup cache file. Note in particular the return value
3537 * is unaffected by a failure to remove extensions.ini
3539 static bool RemoveComponentRegistries(nsIFile* aProfileDir,
3540 nsIFile* aLocalProfileDir,
3541 bool aRemoveEMFiles) {
3542 nsCOMPtr<nsIFile> file;
3543 aProfileDir->Clone(getter_AddRefs(file));
3544 if (!file) return false;
3546 if (aRemoveEMFiles) {
3547 file->SetNativeLeafName("extensions.ini"_ns);
3548 file->Remove(false);
3551 aLocalProfileDir->Clone(getter_AddRefs(file));
3552 if (!file) return false;
3554 file->AppendNative("startupCache"_ns);
3555 nsresult rv = file->Remove(true);
3556 return NS_SUCCEEDED(rv) || rv == NS_ERROR_FILE_NOT_FOUND;
3559 // When we first initialize the crash reporter we don't have a profile,
3560 // so we set the minidump path to $TEMP. Once we have a profile,
3561 // we set it to $PROFILE/minidumps, creating the directory
3562 // if needed.
3563 static void MakeOrSetMinidumpPath(nsIFile* profD) {
3564 nsCOMPtr<nsIFile> dumpD;
3565 profD->Clone(getter_AddRefs(dumpD));
3567 if (dumpD) {
3568 bool fileExists;
3569 // XXX: do some more error checking here
3570 dumpD->Append(u"minidumps"_ns);
3571 dumpD->Exists(&fileExists);
3572 if (!fileExists) {
3573 nsresult rv = dumpD->Create(nsIFile::DIRECTORY_TYPE, 0700);
3574 NS_ENSURE_SUCCESS_VOID(rv);
3577 nsAutoString pathStr;
3578 if (NS_SUCCEEDED(dumpD->GetPath(pathStr)))
3579 CrashReporter::SetMinidumpPath(pathStr);
3583 const XREAppData* gAppData = nullptr;
3586 * NSPR will search for the "nspr_use_zone_allocator" symbol throughout
3587 * the process and use it to determine whether the application defines its own
3588 * memory allocator or not.
3590 * Since most applications (e.g. Firefox and Thunderbird) don't use any special
3591 * allocators and therefore don't define this symbol, NSPR must search the
3592 * entire process, which reduces startup performance.
3594 * By defining the symbol here, we can avoid the wasted lookup and hopefully
3595 * improve startup performance.
3597 NS_VISIBILITY_DEFAULT PRBool nspr_use_zone_allocator = PR_FALSE;
3599 #ifdef CAIRO_HAS_DWRITE_FONT
3601 # include <dwrite.h>
3602 # include "nsWindowsHelpers.h"
3604 # ifdef DEBUG_DWRITE_STARTUP
3606 # define LOGREGISTRY(msg) LogRegistryEvent(msg)
3608 // for use when monitoring process
3609 static void LogRegistryEvent(const wchar_t* msg) {
3610 HKEY dummyKey;
3611 HRESULT hr;
3612 wchar_t buf[512];
3614 wsprintf(buf, L" log %s", msg);
3615 hr = RegOpenKeyEx(HKEY_LOCAL_MACHINE, buf, 0, KEY_READ, &dummyKey);
3616 if (SUCCEEDED(hr)) {
3617 RegCloseKey(dummyKey);
3620 # else
3622 # define LOGREGISTRY(msg)
3624 # endif
3626 static DWORD WINAPI InitDwriteBG(LPVOID lpdwThreadParam) {
3627 SetThreadPriority(GetCurrentThread(), THREAD_MODE_BACKGROUND_BEGIN);
3628 LOGREGISTRY(L"loading dwrite.dll");
3629 HMODULE dwdll = LoadLibrarySystem32(L"dwrite.dll");
3630 if (dwdll) {
3631 decltype(DWriteCreateFactory)* createDWriteFactory =
3632 (decltype(DWriteCreateFactory)*)GetProcAddress(dwdll,
3633 "DWriteCreateFactory");
3634 if (createDWriteFactory) {
3635 LOGREGISTRY(L"creating dwrite factory");
3636 IDWriteFactory* factory;
3637 HRESULT hr = createDWriteFactory(DWRITE_FACTORY_TYPE_SHARED,
3638 __uuidof(IDWriteFactory),
3639 reinterpret_cast<IUnknown**>(&factory));
3640 if (SUCCEEDED(hr)) {
3641 LOGREGISTRY(L"dwrite factory done");
3642 factory->Release();
3643 LOGREGISTRY(L"freed factory");
3644 } else {
3645 LOGREGISTRY(L"failed to create factory");
3649 SetThreadPriority(GetCurrentThread(), THREAD_MODE_BACKGROUND_END);
3650 return 0;
3652 #endif
3654 #include "GeckoProfiler.h"
3655 #include "ProfilerControl.h"
3657 // Encapsulates startup and shutdown state for XRE_main
3658 class XREMain {
3659 public:
3660 XREMain() = default;
3662 ~XREMain() {
3663 mScopedXPCOM = nullptr;
3664 mAppData = nullptr;
3667 int XRE_main(int argc, char* argv[], const BootstrapConfig& aConfig);
3668 int XRE_mainInit(bool* aExitFlag);
3669 int XRE_mainStartup(bool* aExitFlag);
3670 nsresult XRE_mainRun();
3672 bool CheckLastStartupWasCrash();
3674 nsCOMPtr<nsINativeAppSupport> mNativeApp;
3675 RefPtr<nsToolkitProfileService> mProfileSvc;
3676 nsCOMPtr<nsIFile> mProfD;
3677 nsCOMPtr<nsIFile> mProfLD;
3678 nsCOMPtr<nsIProfileLock> mProfileLock;
3679 #if defined(MOZ_HAS_REMOTE)
3680 RefPtr<nsRemoteService> mRemoteService;
3681 #endif
3683 UniquePtr<ScopedXPCOMStartup> mScopedXPCOM;
3684 UniquePtr<XREAppData> mAppData;
3686 nsXREDirProvider mDirProvider;
3688 #ifdef MOZ_WIDGET_GTK
3689 nsAutoCString mXDGActivationToken;
3690 nsAutoCString mDesktopStartupID;
3691 #endif
3693 bool mStartOffline = false;
3694 #if defined(MOZ_HAS_REMOTE)
3695 bool mDisableRemoteClient = false;
3696 bool mDisableRemoteServer = false;
3697 #endif
3700 #if defined(XP_UNIX) && !defined(ANDROID)
3701 static SmprintfPointer FormatUid(uid_t aId) {
3702 if (const auto pw = getpwuid(aId)) {
3703 return mozilla::Smprintf("%s", pw->pw_name);
3705 return mozilla::Smprintf("uid %d", static_cast<int>(aId));
3708 // Bug 1323302: refuse to run under sudo or similar.
3709 static bool CheckForUserMismatch() {
3710 static char const* const kVars[] = {
3711 "HOME",
3712 # ifdef MOZ_WIDGET_GTK
3713 "XDG_RUNTIME_DIR",
3714 # endif
3715 # ifdef MOZ_X11
3716 "XAUTHORITY",
3717 # endif
3720 const uid_t euid = geteuid();
3721 if (euid != 0) {
3722 // On Linux it's possible to have superuser capabilities with a
3723 // nonzero uid, but anyone who knows enough to make that happen
3724 // probably knows enough to debug the resulting problems.
3725 // Otherwise, a non-root user can't cause the problems we're
3726 // concerned about.
3727 return false;
3730 for (const auto var : kVars) {
3731 if (const auto path = PR_GetEnv(var)) {
3732 struct stat st;
3733 if (stat(path, &st) == 0) {
3734 if (st.st_uid != euid) {
3735 const auto owner = FormatUid(st.st_uid);
3736 Output(true,
3737 "Running " MOZ_APP_DISPLAYNAME
3738 " as root in a regular"
3739 " user's session is not supported. ($%s is %s which is"
3740 " owned by %s.)\n",
3741 var, path, owner.get());
3742 return true;
3747 return false;
3749 #else // !XP_UNIX || ANDROID
3750 static bool CheckForUserMismatch() { return false; }
3751 #endif
3753 void mozilla::startup::IncreaseDescriptorLimits() {
3754 #ifdef XP_UNIX
3755 // Increase the fd limit to accomodate IPC resources like shared memory.
3756 // See also the Darwin case in config/external/nspr/pr/moz.build
3757 static const rlim_t kFDs = 4096;
3758 struct rlimit rlim;
3760 if (getrlimit(RLIMIT_NOFILE, &rlim) != 0) {
3761 Output(false, "getrlimit: %s\n", strerror(errno));
3762 return;
3764 // Don't decrease the limit if it's already high enough, but don't
3765 // try to go over the hard limit. (RLIM_INFINITY isn't required to
3766 // be the numerically largest rlim_t, so don't assume that.)
3767 if (rlim.rlim_cur != RLIM_INFINITY && rlim.rlim_cur < kFDs &&
3768 rlim.rlim_cur < rlim.rlim_max) {
3769 if (rlim.rlim_max != RLIM_INFINITY && rlim.rlim_max < kFDs) {
3770 rlim.rlim_cur = rlim.rlim_max;
3771 } else {
3772 rlim.rlim_cur = kFDs;
3774 if (setrlimit(RLIMIT_NOFILE, &rlim) != 0) {
3775 Output(false, "setrlimit: %s\n", strerror(errno));
3778 #endif
3781 #ifdef XP_WIN
3783 static uint32_t GetMicrocodeVersionByVendor(HKEY key, DWORD upper,
3784 DWORD lower) {
3785 WCHAR data[13]; // The CPUID vendor string is 12 characters long plus null
3786 DWORD len = sizeof(data);
3787 DWORD vtype;
3789 if (RegQueryValueExW(key, L"VendorIdentifier", nullptr, &vtype,
3790 reinterpret_cast<LPBYTE>(data), &len) == ERROR_SUCCESS) {
3791 if (wcscmp(L"GenuineIntel", data) == 0) {
3792 // Intel reports the microcode version in the upper 32 bits of the MSR
3793 return upper;
3796 if (wcscmp(L"AuthenticAMD", data) == 0) {
3797 // AMD reports the microcode version in the lower 32 bits of the MSR
3798 return lower;
3801 // Unknown CPU vendor, return whatever half is non-zero
3802 return lower ? lower : upper;
3805 return 0; // No clue
3808 #endif // XP_WIN
3810 static void MaybeAddCPUMicrocodeCrashAnnotation() {
3811 #ifdef XP_WIN
3812 // Add CPU microcode version to the crash report as "CPUMicrocodeVersion".
3813 // It feels like this code may belong in nsSystemInfo instead.
3814 uint32_t cpuUpdateRevision = 0;
3815 HKEY key;
3816 static const WCHAR keyName[] =
3817 L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0";
3819 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, keyName, 0, KEY_QUERY_VALUE, &key) ==
3820 ERROR_SUCCESS) {
3821 DWORD updateRevision[2];
3822 DWORD len = sizeof(updateRevision);
3823 DWORD vtype;
3825 // Windows 7 uses "Update Signature", 8 uses "Update Revision".
3826 // For AMD CPUs, "CurrentPatchLevel" is sometimes used.
3827 // Take the first one we find.
3828 LPCWSTR choices[] = {L"Update Signature", L"Update Revision",
3829 L"CurrentPatchLevel"};
3830 for (const auto& oneChoice : choices) {
3831 if (RegQueryValueExW(key, oneChoice, nullptr, &vtype,
3832 reinterpret_cast<LPBYTE>(updateRevision),
3833 &len) == ERROR_SUCCESS) {
3834 if (vtype == REG_BINARY && len == sizeof(updateRevision)) {
3835 cpuUpdateRevision = GetMicrocodeVersionByVendor(
3836 key, updateRevision[1], updateRevision[0]);
3837 break;
3840 if (vtype == REG_DWORD && len == sizeof(updateRevision[0])) {
3841 cpuUpdateRevision = static_cast<int>(updateRevision[0]);
3842 break;
3848 if (cpuUpdateRevision > 0) {
3849 CrashReporter::AnnotateCrashReport(
3850 CrashReporter::Annotation::CPUMicrocodeVersion,
3851 nsPrintfCString("0x%" PRIx32, cpuUpdateRevision));
3853 #endif
3856 #if defined(MOZ_BACKGROUNDTASKS)
3857 static void SetupConsoleForBackgroundTask(
3858 const nsCString& aBackgroundTaskName) {
3859 // We do not suppress output on Windows because:
3860 // 1. Background task subprocesses launched via LaunchApp() does not attach to
3861 // the console.
3862 // 2. Suppressing output intermittently causes failures on when running
3863 // multiple tasks (see bug 1831631)
3864 # ifndef XP_WIN
3865 if (BackgroundTasks::IsNoOutputTaskName(aBackgroundTaskName) &&
3866 !CheckArg("attach-console") &&
3867 !EnvHasValue("MOZ_BACKGROUNDTASKS_IGNORE_NO_OUTPUT")) {
3868 // Suppress output, somewhat crudely. We need to suppress stderr as well
3869 // as stdout because assertions, of which there are many, write to stderr.
3870 Unused << freopen("/dev/null", "w", stdout);
3871 Unused << freopen("/dev/null", "w", stderr);
3872 return;
3874 # endif
3875 printf_stderr("*** You are running in background task mode. ***\n");
3877 #endif
3880 * XRE_mainInit - Initial setup and command line parameter processing.
3881 * Main() will exit early if either return value != 0 or if aExitFlag is
3882 * true.
3884 int XREMain::XRE_mainInit(bool* aExitFlag) {
3885 if (!aExitFlag) return 1;
3886 *aExitFlag = false;
3888 atexit(UnexpectedExit);
3889 auto expectedShutdown = mozilla::MakeScopeExit([&] { MozExpectedExit(); });
3891 StartupTimeline::Record(StartupTimeline::MAIN);
3893 if (CheckForUserMismatch()) {
3894 return 1;
3897 #ifdef XP_MACOSX
3898 mozilla::MacAutoreleasePool pool;
3900 DisableAppNap();
3901 #endif
3903 #ifdef MOZ_BACKGROUNDTASKS
3904 Maybe<nsCString> backgroundTask = Nothing();
3905 const char* backgroundTaskName = nullptr;
3906 if (ARG_FOUND ==
3907 CheckArg("backgroundtask", &backgroundTaskName, CheckArgFlag::None)) {
3908 backgroundTask = Some(backgroundTaskName);
3910 SetupConsoleForBackgroundTask(backgroundTask.ref());
3913 BackgroundTasks::Init(backgroundTask);
3914 #endif
3916 #ifndef ANDROID
3917 if (PR_GetEnv("MOZ_RUN_GTEST")
3918 # ifdef FUZZING
3919 || PR_GetEnv("FUZZER")
3920 # endif
3921 # ifdef MOZ_BACKGROUNDTASKS
3922 || BackgroundTasks::IsBackgroundTaskMode()
3923 # endif
3925 // Enable headless mode and assert that it worked, since gfxPlatform
3926 // uses a static bool set after the first call to `IsHeadless`.
3927 // Note: Android gtests seem to require an Activity and fail to start
3928 // with headless mode enabled.
3929 PR_SetEnv("MOZ_HEADLESS=1");
3930 MOZ_ASSERT(gfxPlatform::IsHeadless());
3932 #endif // ANDROID
3934 if (PR_GetEnv("MOZ_CHAOSMODE")) {
3935 ChaosFeature feature = ChaosFeature::Any;
3936 long featureInt = strtol(PR_GetEnv("MOZ_CHAOSMODE"), nullptr, 16);
3937 if (featureInt) {
3938 // NOTE: MOZ_CHAOSMODE=0 or a non-hex value maps to Any feature.
3939 feature = static_cast<ChaosFeature>(featureInt);
3941 ChaosMode::SetChaosFeature(feature);
3944 if (CheckArgExists("fxr")) {
3945 gFxREmbedded = true;
3948 if (ChaosMode::isActive(ChaosFeature::Any)) {
3949 printf_stderr(
3950 "*** You are running in chaos test mode. See ChaosMode.h. ***\n");
3953 if (CheckArg("headless") || CheckArgExists("screenshot")) {
3954 PR_SetEnv("MOZ_HEADLESS=1");
3957 if (gfxPlatform::IsHeadless()) {
3958 #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) || defined(XP_MACOSX)
3959 printf_stderr("*** You are running in headless mode.\n");
3960 #else
3961 Output(
3962 true,
3963 "Error: headless mode is not currently supported on this platform.\n");
3964 return 1;
3965 #endif
3967 #ifdef XP_MACOSX
3968 // To avoid taking focus when running in headless mode immediately
3969 // transition Firefox to a background application.
3970 ProcessSerialNumber psn = {0, kCurrentProcess};
3971 OSStatus transformStatus =
3972 TransformProcessType(&psn, kProcessTransformToBackgroundApplication);
3973 if (transformStatus != noErr) {
3974 NS_ERROR("Failed to make process a background application.");
3975 return 1;
3977 #endif
3980 gKioskMode = CheckArg("kiosk", nullptr, CheckArgFlag::None);
3981 const char* kioskMonitorNumber = nullptr;
3982 if (CheckArg("kiosk-monitor", &kioskMonitorNumber, CheckArgFlag::None)) {
3983 gKioskMode = true;
3984 gKioskMonitor = atoi(kioskMonitorNumber);
3987 gAllowContentAnalysis = CheckArg("allow-content-analysis", nullptr,
3988 CheckArgFlag::RemoveArg) == ARG_FOUND;
3990 nsresult rv;
3991 ArgResult ar;
3993 #ifdef DEBUG
3994 if (PR_GetEnv("XRE_MAIN_BREAK")) NS_BREAK();
3995 #endif
3997 mozilla::startup::IncreaseDescriptorLimits();
3999 SetupErrorHandling(gArgv[0]);
4001 #ifdef CAIRO_HAS_DWRITE_FONT
4003 // Bug 602792 - when DWriteCreateFactory is called the dwrite client dll
4004 // starts the FntCache service if it isn't already running (it's set
4005 // to manual startup by default in Windows 7 RTM). Subsequent DirectWrite
4006 // calls cause the IDWriteFactory object to communicate with the FntCache
4007 // service with a timeout; if there's no response after the timeout, the
4008 // DirectWrite client library will assume the service isn't around and do
4009 // manual font file I/O on _all_ system fonts. To avoid this, load the
4010 // dwrite library and create a factory as early as possible so that the
4011 // FntCache service is ready by the time it's needed.
4013 CreateThread(nullptr, 0, &InitDwriteBG, nullptr, 0, nullptr);
4015 #endif
4017 #ifdef XP_UNIX
4018 const char* home = PR_GetEnv("HOME");
4019 if (!home || !*home) {
4020 struct passwd* pw = getpwuid(geteuid());
4021 if (!pw || !pw->pw_dir) {
4022 Output(true, "Could not determine HOME directory");
4023 return 1;
4025 SaveWordToEnv("HOME", nsDependentCString(pw->pw_dir));
4027 #endif
4029 #ifdef MOZ_ACCESSIBILITY_ATK
4030 // Suppress atk-bridge init at startup, until mozilla accessibility is
4031 // initialized. This works after gnome 2.24.2.
4032 SaveToEnv("NO_AT_BRIDGE=1");
4033 #endif
4035 // Check for application.ini overrides
4036 const char* override = nullptr;
4037 ar = CheckArg("override", &override);
4038 if (ar == ARG_BAD) {
4039 Output(true, "Incorrect number of arguments passed to --override");
4040 return 1;
4042 if (ar == ARG_FOUND) {
4043 nsCOMPtr<nsIFile> overrideLF;
4044 rv = XRE_GetFileFromPath(override, getter_AddRefs(overrideLF));
4045 if (NS_FAILED(rv)) {
4046 Output(true, "Error: unrecognized override.ini path.\n");
4047 return 1;
4050 rv = XRE_ParseAppData(overrideLF, *mAppData);
4051 if (NS_FAILED(rv)) {
4052 Output(true, "Couldn't read override.ini");
4053 return 1;
4057 // Check sanity and correctness of app data.
4059 if (!mAppData->name) {
4060 Output(true, "Error: App:Name not specified in application.ini\n");
4061 return 1;
4063 if (!mAppData->buildID) {
4064 Output(true, "Error: App:BuildID not specified in application.ini\n");
4065 return 1;
4068 // XXX Originally ScopedLogging was here? Now it's in XRE_main above
4069 // XRE_mainInit.
4071 if (!mAppData->minVersion) {
4072 Output(true, "Error: Gecko:MinVersion not specified in application.ini\n");
4073 return 1;
4076 if (!mAppData->maxVersion) {
4077 // If no maxVersion is specified, we assume the app is only compatible
4078 // with the initial preview release. Do not increment this number ever!
4079 mAppData->maxVersion = "1.*";
4082 if (mozilla::Version(mAppData->minVersion) > gToolkitVersion ||
4083 mozilla::Version(mAppData->maxVersion) < gToolkitVersion) {
4084 Output(true,
4085 "Error: Platform version '%s' is not compatible with\n"
4086 "minVersion >= %s\nmaxVersion <= %s\n",
4087 (const char*)gToolkitVersion, (const char*)mAppData->minVersion,
4088 (const char*)mAppData->maxVersion);
4089 return 1;
4092 rv = mDirProvider.Initialize(mAppData->directory, mAppData->xreDirectory);
4093 if (NS_FAILED(rv)) return 1;
4095 if (EnvHasValue("MOZ_CRASHREPORTER")) {
4096 mAppData->flags |= NS_XRE_ENABLE_CRASH_REPORTER;
4099 nsCOMPtr<nsIFile> xreBinDirectory;
4100 xreBinDirectory = mDirProvider.GetGREBinDir();
4102 if ((mAppData->flags & NS_XRE_ENABLE_CRASH_REPORTER) &&
4103 NS_SUCCEEDED(CrashReporter::SetExceptionHandler(xreBinDirectory))) {
4104 nsCOMPtr<nsIFile> file;
4105 rv = nsXREDirProvider::GetUserAppDataDirectory(getter_AddRefs(file));
4106 if (NS_SUCCEEDED(rv)) {
4107 CrashReporter::SetUserAppDataDirectory(file);
4109 if (mAppData->crashReporterURL)
4110 CrashReporter::SetServerURL(
4111 nsDependentCString(mAppData->crashReporterURL));
4113 // We overwrite this once we finish starting up.
4114 CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::StartupCrash,
4115 true);
4117 // pass some basic info from the app data
4118 if (mAppData->vendor)
4119 CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::Vendor,
4120 nsDependentCString(mAppData->vendor));
4121 if (mAppData->name)
4122 CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::ProductName,
4123 nsDependentCString(mAppData->name));
4124 if (mAppData->ID)
4125 CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::ProductID,
4126 nsDependentCString(mAppData->ID));
4127 if (mAppData->version)
4128 CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::Version,
4129 nsDependentCString(mAppData->version));
4130 if (mAppData->buildID)
4131 CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::BuildID,
4132 nsDependentCString(mAppData->buildID));
4134 nsDependentCString releaseChannel(MOZ_STRINGIFY(MOZ_UPDATE_CHANNEL));
4135 CrashReporter::AnnotateCrashReport(
4136 CrashReporter::Annotation::ReleaseChannel, releaseChannel);
4138 #ifdef XP_WIN
4139 nsAutoString appInitDLLs;
4140 if (widget::WinUtils::GetAppInitDLLs(appInitDLLs)) {
4141 CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::AppInitDLLs,
4142 NS_ConvertUTF16toUTF8(appInitDLLs));
4145 nsString packageFamilyName = widget::WinUtils::GetPackageFamilyName();
4146 if (StringBeginsWith(packageFamilyName, u"Mozilla."_ns) ||
4147 StringBeginsWith(packageFamilyName, u"MozillaCorporation."_ns)) {
4148 CrashReporter::AnnotateCrashReport(
4149 CrashReporter::Annotation::WindowsPackageFamilyName,
4150 NS_ConvertUTF16toUTF8(packageFamilyName));
4152 #endif
4154 bool isBackgroundTaskMode = false;
4155 #ifdef MOZ_BACKGROUNDTASKS
4156 Maybe<nsCString> backgroundTasks = BackgroundTasks::GetBackgroundTasks();
4157 if (backgroundTasks.isSome()) {
4158 isBackgroundTaskMode = true;
4159 CrashReporter::AnnotateCrashReport(
4160 CrashReporter::Annotation::BackgroundTaskName, backgroundTasks.ref());
4162 #endif
4163 CrashReporter::AnnotateCrashReport(
4164 CrashReporter::Annotation::BackgroundTaskMode, isBackgroundTaskMode);
4166 CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::HeadlessMode,
4167 gfxPlatform::IsHeadless());
4169 CrashReporter::SetRestartArgs(gArgc, gArgv);
4171 // annotate other data (user id etc)
4172 nsCOMPtr<nsIFile> userAppDataDir;
4173 if (NS_SUCCEEDED(mDirProvider.GetUserAppDataDirectory(
4174 getter_AddRefs(userAppDataDir)))) {
4175 CrashReporter::SetupExtraData(userAppDataDir,
4176 nsDependentCString(mAppData->buildID));
4178 // see if we have a crashreporter-override.ini in the application
4179 // directory
4180 nsCOMPtr<nsIFile> overrideini;
4181 if (NS_SUCCEEDED(
4182 mDirProvider.GetAppDir()->Clone(getter_AddRefs(overrideini))) &&
4183 NS_SUCCEEDED(
4184 overrideini->AppendNative("crashreporter-override.ini"_ns))) {
4185 #ifdef XP_WIN
4186 nsAutoString overridePathW;
4187 overrideini->GetPath(overridePathW);
4188 NS_ConvertUTF16toUTF8 overridePath(overridePathW);
4189 #else
4190 nsAutoCString overridePath;
4191 overrideini->GetNativePath(overridePath);
4192 #endif
4194 SaveWordToEnv("MOZ_CRASHREPORTER_STRINGS_OVERRIDE", overridePath);
4197 } else {
4198 // We might have registered a runtime exception module very early in process
4199 // startup to catch early crashes. This is before we have access to ini file
4200 // data, so unregister here if it turns out the crash reporter is disabled.
4201 CrashReporter::UnregisterRuntimeExceptionModule();
4204 #if defined(MOZ_SANDBOX) && defined(XP_WIN)
4205 if (mAppData->sandboxBrokerServices) {
4206 SandboxBroker::Initialize(mAppData->sandboxBrokerServices);
4207 } else {
4208 # if defined(MOZ_SANDBOX)
4209 // If we're sandboxing content and we fail to initialize, then crashing here
4210 // seems like the sensible option.
4211 if (BrowserTabsRemoteAutostart()) {
4212 MOZ_CRASH("Failed to initialize broker services, can't continue.");
4214 # endif
4215 // Otherwise just warn for the moment, as most things will work.
4216 NS_WARNING(
4217 "Failed to initialize broker services, sandboxed processes will "
4218 "fail to start.");
4220 #endif
4222 #ifdef XP_MACOSX
4223 // Set up ability to respond to system (Apple) events. This must occur before
4224 // ProcessUpdates to ensure that links clicked in external applications aren't
4225 // lost when updates are pending.
4226 SetupMacApplicationDelegate(&gRestartedByOS);
4228 if (EnvHasValue("MOZ_LAUNCHED_CHILD")) {
4229 // This is needed, on relaunch, to force the OS to use the "Cocoa Dock
4230 // API". Otherwise the call to ReceiveNextEvent() below will make it
4231 // use the "Carbon Dock API". For more info see bmo bug 377166.
4232 EnsureUseCocoaDockAPI();
4234 // When the app relaunches, the original process exits. This causes
4235 // the dock tile to stop bouncing, lose the "running" triangle, and
4236 // if the tile does not permanently reside in the Dock, even disappear.
4237 // This can be confusing to the user, who is expecting the app to launch.
4238 // Calling ReceiveNextEvent without requesting any event is enough to
4239 // cause a dock tile for the child process to appear.
4240 const EventTypeSpec kFakeEventList[] = {{INT_MAX, INT_MAX}};
4241 EventRef event;
4242 ::ReceiveNextEvent(GetEventTypeCount(kFakeEventList), kFakeEventList,
4243 kEventDurationNoWait, false, &event);
4246 if (CheckArg("foreground")) {
4247 // The original process communicates that it was in the foreground by
4248 // adding this argument. This new process, which is taking over for
4249 // the old one, should make itself the active application.
4250 ProcessSerialNumber psn;
4251 if (::GetCurrentProcess(&psn) == noErr) ::SetFrontProcess(&psn);
4253 #endif
4255 SaveToEnv("MOZ_LAUNCHED_CHILD=");
4257 // On Windows, the -os-restarted command line switch lets us know when we are
4258 // restarted via RegisterApplicationRestart. May be used for other OSes later.
4259 if (CheckArg("os-restarted", nullptr, CheckArgFlag::RemoveArg) == ARG_FOUND) {
4260 gRestartedByOS = true;
4263 gRestartArgc = gArgc;
4264 gRestartArgv =
4265 (char**)malloc(sizeof(char*) * (gArgc + 1 + (override ? 2 : 0)));
4266 if (!gRestartArgv) {
4267 return 1;
4270 int i;
4271 for (i = 0; i < gArgc; ++i) {
4272 gRestartArgv[i] = gArgv[i];
4275 // Add the -override argument back (it is removed automatically be CheckArg)
4276 // if there is one
4277 if (override) {
4278 gRestartArgv[gRestartArgc++] = const_cast<char*>("-override");
4279 gRestartArgv[gRestartArgc++] = const_cast<char*>(override);
4282 gRestartArgv[gRestartArgc] = nullptr;
4284 Maybe<bool> safeModeRequested = IsSafeModeRequested(gArgc, gArgv);
4285 if (!safeModeRequested) {
4286 return 1;
4288 #ifdef MOZ_BACKGROUNDTASKS
4289 if (BackgroundTasks::IsBackgroundTaskMode()) {
4290 safeModeRequested = Some(false);
4292 // Remove the --backgroundtask arg now that it has been saved in
4293 // gRestartArgv.
4294 const char* tmpBackgroundTaskName = nullptr;
4295 Unused << CheckArg("backgroundtask", &tmpBackgroundTaskName,
4296 CheckArgFlag::RemoveArg);
4298 #endif
4300 gSafeMode = safeModeRequested.value();
4302 MaybeAddCPUMicrocodeCrashAnnotation();
4303 CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::SafeMode,
4304 gSafeMode);
4306 #if defined(MOZ_HAS_REMOTE)
4307 // Handle --no-remote and --new-instance command line arguments. Setup
4308 // the environment to better accommodate other components and various
4309 // restart scenarios.
4310 ar = CheckArg("no-remote");
4311 if (ar == ARG_FOUND || EnvHasValue("MOZ_NO_REMOTE")) {
4312 mDisableRemoteClient = true;
4313 mDisableRemoteServer = true;
4314 gRestartWithoutRemote = true;
4315 // We don't want to propagate MOZ_NO_REMOTE to potential child
4316 // process.
4317 SaveToEnv("MOZ_NO_REMOTE=");
4320 ar = CheckArg("new-instance");
4321 if (ar == ARG_FOUND || EnvHasValue("MOZ_NEW_INSTANCE")) {
4322 mDisableRemoteClient = true;
4324 #else
4325 // These arguments do nothing in platforms with no remoting support but we
4326 // should remove them from the command line anyway.
4327 CheckArg("no-remote");
4328 CheckArg("new-instance");
4329 #endif
4331 ar = CheckArg("offline");
4332 if (ar || EnvHasValue("XRE_START_OFFLINE")) {
4333 mStartOffline = true;
4336 // On Windows, to get working console arrangements so help/version/etc
4337 // print something, we need to initialize the native app support.
4338 rv = NS_CreateNativeAppSupport(getter_AddRefs(mNativeApp));
4339 if (NS_FAILED(rv)) return 1;
4341 // Handle --help, --full-version and --version command line arguments.
4342 // They should return quickly, so we deal with them here.
4343 if (CheckArg("h") || CheckArg("help") || CheckArg("?")) {
4344 DumpHelp();
4345 *aExitFlag = true;
4346 return 0;
4349 if (CheckArg("v") || CheckArg("version")) {
4350 DumpVersion();
4351 *aExitFlag = true;
4352 return 0;
4355 if (CheckArg("full-version")) {
4356 DumpFullVersion();
4357 *aExitFlag = true;
4358 return 0;
4361 rv = XRE_InitCommandLine(gArgc, gArgv);
4362 NS_ENSURE_SUCCESS(rv, 1);
4364 return 0;
4367 #if defined(XP_LINUX) && !defined(ANDROID)
4369 static void AnnotateLSBRelease(void*) {
4370 nsCString dist, desc, release, codename;
4371 if (widget::lsb::GetLSBRelease(dist, desc, release, codename)) {
4372 CrashReporter::AppendAppNotesToCrashReport(desc);
4376 #endif // defined(XP_LINUX) && !defined(ANDROID)
4378 #ifdef XP_WIN
4379 static void ReadAheadSystemDll(const wchar_t* dllName) {
4380 wchar_t dllPath[MAX_PATH];
4381 if (ConstructSystem32Path(dllName, dllPath, MAX_PATH)) {
4382 ReadAheadLib(dllPath);
4386 static void ReadAheadPackagedDll(const wchar_t* dllName,
4387 const wchar_t* aGREDir) {
4388 wchar_t dllPath[MAX_PATH];
4389 swprintf(dllPath, MAX_PATH, L"%s\\%s", aGREDir, dllName);
4390 ReadAheadLib(dllPath);
4393 static void PR_CALLBACK ReadAheadDlls_ThreadStart(void* arg) {
4394 UniquePtr<wchar_t[]> greDir(static_cast<wchar_t*>(arg));
4396 // In Bug 1628903, we investigated which DLLs we should prefetch in
4397 // order to reduce disk I/O and improve startup on Windows machines.
4398 // Our ultimate goal is to measure the impact of these improvements on
4399 // retention (see Bug 1640087). Before we place this within a pref,
4400 // we should ensure this feature only ships to the nightly channel
4401 // and monitor results from that subset.
4402 if (greDir) {
4403 // Prefetch the DLLs shipped with firefox
4404 ReadAheadPackagedDll(L"libegl.dll", greDir.get());
4405 ReadAheadPackagedDll(L"libGLESv2.dll", greDir.get());
4406 ReadAheadPackagedDll(L"nssckbi.dll", greDir.get());
4407 ReadAheadPackagedDll(L"freebl3.dll", greDir.get());
4408 ReadAheadPackagedDll(L"softokn3.dll", greDir.get());
4410 // Prefetch the system DLLs
4411 ReadAheadSystemDll(L"DWrite.dll");
4412 ReadAheadSystemDll(L"D3DCompiler_47.dll");
4413 } else {
4414 // Load DataExchange.dll and twinapi.appcore.dll for
4415 // nsWindow::EnableDragDrop
4416 ReadAheadSystemDll(L"DataExchange.dll");
4417 ReadAheadSystemDll(L"twinapi.appcore.dll");
4419 // Load twinapi.dll for WindowsUIUtils::UpdateTabletModeState
4420 ReadAheadSystemDll(L"twinapi.dll");
4422 // Load explorerframe.dll for WinTaskbar::Initialize
4423 ReadAheadSystemDll(L"ExplorerFrame.dll");
4425 // Load WinTypes.dll for nsOSHelperAppService::GetApplicationDescription
4426 ReadAheadSystemDll(L"WinTypes.dll");
4429 #endif
4431 #if defined(MOZ_UPDATER) && !defined(MOZ_WIDGET_ANDROID)
4432 enum struct ShouldNotProcessUpdatesReason {
4433 DevToolsLaunching,
4434 NotAnUpdatingTask,
4435 OtherInstanceRunning,
4436 FirstStartup
4439 const char* ShouldNotProcessUpdatesReasonAsString(
4440 ShouldNotProcessUpdatesReason aReason) {
4441 switch (aReason) {
4442 case ShouldNotProcessUpdatesReason::DevToolsLaunching:
4443 return "DevToolsLaunching";
4444 case ShouldNotProcessUpdatesReason::NotAnUpdatingTask:
4445 return "NotAnUpdatingTask";
4446 case ShouldNotProcessUpdatesReason::OtherInstanceRunning:
4447 return "OtherInstanceRunning";
4448 default:
4449 MOZ_CRASH("impossible value for ShouldNotProcessUpdatesReason");
4453 Maybe<ShouldNotProcessUpdatesReason> ShouldNotProcessUpdates(
4454 nsXREDirProvider& aDirProvider) {
4455 // Don't process updates when launched from the installer.
4456 // It's possible for a stale update to be present in the case of a paveover;
4457 // ignore it and leave the update service to discard it.
4458 if (ARG_FOUND == CheckArgExists("first-startup")) {
4459 NS_WARNING("ShouldNotProcessUpdates(): FirstStartup");
4460 return Some(ShouldNotProcessUpdatesReason::FirstStartup);
4463 // Do not process updates if we're launching devtools, as evidenced by
4464 // "--chrome ..." with the browser toolbox chrome document URL.
4466 // Keep this synchronized with the value of the same name in
4467 // devtools/client/framework/browser-toolbox/Launcher.sys.mjs. Or, for bonus
4468 // points, lift this value to nsIXulRuntime or similar, so that it can be
4469 // accessed in both locations. (The prefs service isn't available at this
4470 // point so the simplest manner of sharing the value is not available to us.)
4471 const char* BROWSER_TOOLBOX_WINDOW_URL =
4472 "chrome://devtools/content/framework/browser-toolbox/window.html";
4474 const char* chromeParam = nullptr;
4475 if (ARG_FOUND == CheckArg("chrome", &chromeParam, CheckArgFlag::None)) {
4476 if (!chromeParam || !strcmp(BROWSER_TOOLBOX_WINDOW_URL, chromeParam)) {
4477 NS_WARNING("ShouldNotProcessUpdates(): DevToolsLaunching");
4478 return Some(ShouldNotProcessUpdatesReason::DevToolsLaunching);
4482 # ifdef MOZ_BACKGROUNDTASKS
4483 // Do not process updates if we're running a background task mode and another
4484 // instance is already running. This avoids periodic maintenance updating
4485 // underneath a browsing session.
4486 Maybe<nsCString> backgroundTasks = BackgroundTasks::GetBackgroundTasks();
4487 if (backgroundTasks.isSome()) {
4488 // Only process updates for specific tasks: at this time, the
4489 // `backgroundupdate` task and the test-only `shouldprocessupdates` task.
4491 // Background tasks can be sparked by Firefox instances that are shutting
4492 // down, which can cause races between the task startup trying to update and
4493 // Firefox trying to invoke the updater. This happened when converting
4494 // `pingsender` to a background task, since it is launched to send pings at
4495 // shutdown: Bug 1736373.
4497 // We'd prefer to have this be a property of the task definition sibling to
4498 // `backgroundTaskTimeoutSec`, but when we reach this code we're well before
4499 // we can load the task JSM.
4500 if (!BackgroundTasks::IsUpdatingTaskName(backgroundTasks.ref())) {
4501 NS_WARNING("ShouldNotProcessUpdates(): NotAnUpdatingTask");
4502 return Some(ShouldNotProcessUpdatesReason::NotAnUpdatingTask);
4505 // At this point we have a dir provider but no XPCOM directory service. We
4506 // launch the update sync manager using that information so that it doesn't
4507 // need to ask for (and fail to find) the directory service.
4508 nsCOMPtr<nsIFile> anAppFile;
4509 bool persistent;
4510 nsresult rv = aDirProvider.GetFile(XRE_EXECUTABLE_FILE, &persistent,
4511 getter_AddRefs(anAppFile));
4512 if (NS_FAILED(rv) || !anAppFile) {
4513 // Strange, but not a reason to skip processing updates.
4514 return Nothing();
4517 auto updateSyncManager = new nsUpdateSyncManager(anAppFile);
4519 bool otherInstance = false;
4520 updateSyncManager->IsOtherInstanceRunning(&otherInstance);
4521 if (otherInstance) {
4522 NS_WARNING("ShouldNotProcessUpdates(): OtherInstanceRunning");
4523 return Some(ShouldNotProcessUpdatesReason::OtherInstanceRunning);
4526 # endif
4528 return Nothing();
4530 #endif
4532 namespace mozilla::startup {
4533 Result<nsCOMPtr<nsIFile>, nsresult> GetIncompleteStartupFile(nsIFile* aProfLD) {
4534 nsCOMPtr<nsIFile> crashFile;
4535 MOZ_TRY(aProfLD->Clone(getter_AddRefs(crashFile)));
4536 MOZ_TRY(crashFile->Append(FILE_STARTUP_INCOMPLETE));
4537 return std::move(crashFile);
4539 } // namespace mozilla::startup
4541 // Check whether the last startup attempt resulted in a crash or hang.
4542 // This is distinct from the definition of a startup crash from
4543 // nsAppStartup::TrackStartupCrashBegin.
4544 bool XREMain::CheckLastStartupWasCrash() {
4545 Result<nsCOMPtr<nsIFile>, nsresult> crashFile =
4546 GetIncompleteStartupFile(mProfLD);
4547 if (crashFile.isErr()) {
4548 return true;
4551 // Attempt to create the incomplete startup canary file. If the file already
4552 // exists, this fails, and we know the last startup was a crash. If it
4553 // doesn't already exist, it is created, and will be removed at the end of
4554 // the startup crash detection window.
4555 AutoFDClose fd;
4556 Unused << crashFile.inspect()->OpenNSPRFileDesc(
4557 PR_WRONLY | PR_CREATE_FILE | PR_EXCL, 0666, getter_Transfers(fd));
4558 return !fd;
4562 * XRE_mainStartup - Initializes the profile and various other services.
4563 * Main() will exit early if either return value != 0 or if aExitFlag is
4564 * true.
4566 int XREMain::XRE_mainStartup(bool* aExitFlag) {
4567 nsresult rv;
4569 if (!aExitFlag) return 1;
4570 *aExitFlag = false;
4572 #ifdef XP_MACOSX
4573 mozilla::MacAutoreleasePool pool;
4574 #endif
4576 // Enable Telemetry IO Reporting on DEBUG, nightly and local builds,
4577 // but disable it on FUZZING builds and for ANDROID.
4578 #ifndef FUZZING
4579 # ifndef ANDROID
4580 # ifdef DEBUG
4581 mozilla::Telemetry::InitIOReporting(gAppData->xreDirectory);
4582 # else
4584 const char* releaseChannel = MOZ_STRINGIFY(MOZ_UPDATE_CHANNEL);
4585 if (strcmp(releaseChannel, "nightly") == 0 ||
4586 strcmp(releaseChannel, "default") == 0) {
4587 mozilla::Telemetry::InitIOReporting(gAppData->xreDirectory);
4590 # endif /* DEBUG */
4591 # endif /* ANDROID */
4592 #endif /* FUZZING */
4594 #if defined(XP_WIN)
4595 // Enable the HeapEnableTerminationOnCorruption exploit mitigation. We ignore
4596 // the return code because it always returns success, although it has no
4597 // effect on Windows older than XP SP3.
4598 HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);
4599 #endif /* XP_WIN */
4601 #ifdef MOZ_WIDGET_GTK
4602 // Stash startup token in owned memory because gtk_init will clear
4603 // DESKTOP_STARTUP_ID it.
4604 if (const char* v = PR_GetEnv("DESKTOP_STARTUP_ID")) {
4605 mDesktopStartupID.Assign(v);
4607 if (const char* v = PR_GetEnv("XDG_ACTIVATION_TOKEN")) {
4608 mXDGActivationToken.Assign(v);
4610 #endif
4612 #if defined(XP_WIN)
4614 // Save the shortcut path before lpTitle is replaced by an AUMID,
4615 // such as by WinTaskbar
4616 STARTUPINFOW si;
4617 GetStartupInfoW(&si);
4618 if (si.dwFlags & STARTF_TITLEISAPPID) {
4619 NS_WARNING("AUMID was already set, shortcut may have been lost.");
4620 } else if ((si.dwFlags & STARTF_TITLEISLINKNAME) && si.lpTitle) {
4621 gProcessStartupShortcut.Assign(si.lpTitle);
4624 #endif /* XP_WIN */
4626 #if defined(MOZ_WIDGET_GTK)
4627 // setup for private colormap. Ideally we'd like to do this
4628 // in nsAppShell::Create, but we need to get in before gtk
4629 // has been initialized to make sure everything is running
4630 // consistently.
4632 // Set program name to the one defined in application.ini.
4633 g_set_prgname(gAppData->remotingName);
4635 // Initialize GTK here for splash.
4637 # if defined(MOZ_WIDGET_GTK) && defined(MOZ_X11)
4638 // Disable XInput2 multidevice support due to focus bugginess.
4639 // See bugs 1182700, 1170342.
4640 // gdk_disable_multidevice() affects Gdk X11 backend only,
4641 // the multidevice support is always enabled on Wayland backend.
4642 const char* useXI2 = PR_GetEnv("MOZ_USE_XINPUT2");
4643 if (!useXI2 || (*useXI2 == '0')) gdk_disable_multidevice();
4644 # endif
4646 // Open the display ourselves instead of using gtk_init, so that we can
4647 // close it without fear that one day gtk might clean up the display it
4648 // opens.
4649 if (!gtk_parse_args(&gArgc, &gArgv)) return 1;
4650 #endif /* MOZ_WIDGET_GTK */
4652 #ifdef FUZZING
4653 if (PR_GetEnv("FUZZER")) {
4654 *aExitFlag = true;
4655 return mozilla::fuzzerRunner->Run(&gArgc, &gArgv);
4657 #endif
4659 if (PR_GetEnv("MOZ_RUN_GTEST")) {
4660 int result;
4661 #ifdef XP_WIN
4662 UseParentConsole();
4663 #endif
4664 // RunGTest will only be set if we're in xul-unit
4665 if (mozilla::RunGTest) {
4666 gIsGtest = true;
4667 result = mozilla::RunGTest(&gArgc, gArgv);
4668 gIsGtest = false;
4669 } else {
4670 result = 1;
4671 printf("TEST-UNEXPECTED-FAIL | gtest | Not compiled with enable-tests\n");
4673 *aExitFlag = true;
4674 return result;
4677 bool isBackgroundTaskMode = false;
4678 #ifdef MOZ_BACKGROUNDTASKS
4679 isBackgroundTaskMode = BackgroundTasks::IsBackgroundTaskMode();
4680 #endif
4682 #ifdef MOZ_HAS_REMOTE
4683 if (gfxPlatform::IsHeadless()) {
4684 mDisableRemoteClient = true;
4685 mDisableRemoteServer = true;
4687 #endif
4689 #ifdef MOZ_X11
4690 // Init X11 in thread-safe mode. Must be called prior to the first call to
4691 // XOpenDisplay (called inside gdk_display_open). This is a requirement for
4692 // off main tread compositing.
4693 if (!isBackgroundTaskMode && !gfxPlatform::IsHeadless()) {
4694 XInitThreads();
4696 #endif
4697 #if defined(MOZ_WIDGET_GTK)
4698 if (!isBackgroundTaskMode && !gfxPlatform::IsHeadless()) {
4699 const char* display_name = nullptr;
4700 bool saveDisplayArg = false;
4702 // display_name is owned by gdk.
4703 display_name = gdk_get_display_arg_name();
4704 bool waylandEnabled = IsWaylandEnabled();
4705 # ifdef MOZ_WAYLAND
4706 if (!display_name) {
4707 auto* proxyEnv = getenv("MOZ_DISABLE_WAYLAND_PROXY");
4708 bool disableWaylandProxy = proxyEnv && *proxyEnv;
4709 if (!disableWaylandProxy && XRE_IsParentProcess() && waylandEnabled) {
4710 # ifdef MOZ_LOGGING
4711 if (MOZ_LOG_TEST(gWidgetWaylandLog, mozilla::LogLevel::Debug)) {
4712 WaylandProxy::SetVerbose(true);
4714 # endif
4715 gWaylandProxy = WaylandProxy::Create();
4716 if (gWaylandProxy) {
4717 gWaylandProxy->RunThread();
4721 # endif
4723 // if --display argument is given make sure it's
4724 // also passed to ContentChild::Init() by MOZ_GDK_DISPLAY.
4725 if (display_name) {
4726 SaveWordToEnv("MOZ_GDK_DISPLAY", nsDependentCString(display_name));
4727 saveDisplayArg = true;
4730 // On Wayland disabled builds read X11 DISPLAY env exclusively
4731 // and don't care about different displays.
4732 if (!waylandEnabled && !display_name) {
4733 display_name = PR_GetEnv("DISPLAY");
4734 if (!display_name) {
4735 PR_fprintf(PR_STDERR,
4736 "Error: no DISPLAY environment variable specified\n");
4737 return 1;
4741 if (display_name) {
4742 GdkDisplay* disp = gdk_display_open(display_name);
4743 if (!disp) {
4744 PR_fprintf(PR_STDERR, "Error: cannot open display: %s\n", display_name);
4745 return 1;
4747 if (saveDisplayArg) {
4748 if (GdkIsX11Display(disp)) {
4749 SaveWordToEnv("DISPLAY", nsDependentCString(display_name));
4751 # ifdef MOZ_WAYLAND
4752 else if (GdkIsWaylandDisplay(disp)) {
4753 SaveWordToEnv("WAYLAND_DISPLAY", nsDependentCString(display_name));
4755 # endif
4758 # ifdef MOZ_WIDGET_GTK
4759 else {
4760 gdk_display_manager_open_display(gdk_display_manager_get(), nullptr);
4762 # endif
4763 // Check that Wayland only and X11 only builds
4764 // use appropriate displays.
4765 # if defined(MOZ_WAYLAND) && !defined(MOZ_X11)
4766 if (!GdkIsWaylandDisplay()) {
4767 Output(true, "Wayland only build is missig Wayland display!\n");
4769 # endif
4770 # if !defined(MOZ_WAYLAND) && defined(MOZ_X11)
4771 if (!GdkIsX11Display()) {
4772 Output(true, "X11 only build is missig X11 display!\n");
4774 # endif
4775 # if defined(MOZ_WAYLAND)
4776 // We want to use proxy for main connection only so
4777 // restore original Wayland display for next potential Wayland connections
4778 // from gfx probe code and so on.
4779 if (gWaylandProxy) {
4780 gWaylandProxy->RestoreWaylandDisplay();
4782 # endif
4784 #endif
4785 #if defined(MOZ_HAS_REMOTE)
4786 // handle --remote now that xpcom is fired up
4787 mRemoteService = new nsRemoteService(gAppData->remotingName);
4788 if (mRemoteService && !mDisableRemoteServer) {
4789 mRemoteService->LockStartup();
4790 gRemoteService = mRemoteService;
4792 #endif
4793 #if defined(MOZ_WIDGET_GTK)
4794 g_set_application_name(mAppData->name);
4796 #endif /* defined(MOZ_WIDGET_GTK) */
4797 #ifdef MOZ_X11
4798 // Do this after initializing GDK, or GDK will install its own handler.
4799 XRE_InstallX11ErrorHandler();
4800 #endif
4802 // Call the code to install our handler
4803 #ifdef MOZ_JPROF
4804 setupProfilingStuff();
4805 #endif
4807 bool canRun = false;
4808 rv = mNativeApp->Start(&canRun);
4809 if (NS_FAILED(rv) || !canRun) {
4810 return 1;
4813 #ifdef MOZ_WIDGET_GTK
4814 // startup token might be cleared now, we recover it in case we need a
4815 // restart.
4816 if (!mDesktopStartupID.IsEmpty()) {
4817 // Leak it with extreme prejudice!
4818 PR_SetEnv(ToNewCString("DESKTOP_STARTUP_ID="_ns + mDesktopStartupID));
4821 if (!mXDGActivationToken.IsEmpty()) {
4822 // Leak it with extreme prejudice!
4823 PR_SetEnv(ToNewCString("XDG_ACTIVATION_TOKEN="_ns + mXDGActivationToken));
4825 #endif
4827 // Support exiting early for testing startup sequence. Bug 1360493
4828 if (CheckArg("test-launch-without-hang")) {
4829 *aExitFlag = true;
4830 return 0;
4833 mProfileSvc = NS_GetToolkitProfileService();
4834 if (!mProfileSvc) {
4835 // We failed to choose or create profile - notify user and quit
4836 ProfileMissingDialog(mNativeApp);
4837 return 1;
4840 bool wasDefaultSelection;
4841 nsCOMPtr<nsIToolkitProfile> profile;
4842 rv = SelectProfile(mProfileSvc, mNativeApp, getter_AddRefs(mProfD),
4843 getter_AddRefs(mProfLD), getter_AddRefs(profile),
4844 &wasDefaultSelection);
4845 if (rv == NS_ERROR_LAUNCHED_CHILD_PROCESS || rv == NS_ERROR_ABORT) {
4846 *aExitFlag = true;
4847 return 0;
4850 if (NS_FAILED(rv)) {
4851 // We failed to choose or create profile - notify user and quit
4852 ProfileMissingDialog(mNativeApp);
4853 return 1;
4856 #if defined(MOZ_HAS_REMOTE)
4857 if (mRemoteService) {
4858 // We want a unique profile name to identify the remote instance.
4859 nsCString profileName;
4860 if (profile) {
4861 rv = profile->GetName(profileName);
4863 if (!profile || NS_FAILED(rv) || profileName.IsEmpty()) {
4864 // Couldn't get a name from the profile. Use the directory name?
4865 nsString leafName;
4866 rv = mProfD->GetLeafName(leafName);
4867 if (NS_SUCCEEDED(rv)) {
4868 CopyUTF16toUTF8(leafName, profileName);
4872 mRemoteService->SetProfile(profileName);
4874 if (!mDisableRemoteClient) {
4875 // Try to remote the entire command line. If this fails, start up
4876 // normally.
4877 # ifdef MOZ_WIDGET_GTK
4878 const auto& startupToken =
4879 GdkIsWaylandDisplay() ? mXDGActivationToken : mDesktopStartupID;
4880 # else
4881 const nsCString startupToken;
4882 # endif
4883 RemoteResult rr = mRemoteService->StartClient(
4884 startupToken.IsEmpty() ? nullptr : startupToken.get());
4885 if (rr == REMOTE_FOUND) {
4886 *aExitFlag = true;
4887 mRemoteService->UnlockStartup();
4888 return 0;
4890 if (rr == REMOTE_ARG_BAD) {
4891 mRemoteService->UnlockStartup();
4892 return 1;
4896 #endif
4898 #if defined(MOZ_UPDATER) && !defined(MOZ_WIDGET_ANDROID)
4899 # ifdef XP_WIN
4901 // When automatically restarting for a staged background update
4902 // we want the child process to wait here so that the updater
4903 // does not register two instances running and use that as a
4904 // reason to not process updates. This function requires having
4905 // -restart-pid <param> in the command line to function properly.
4906 // Ensure we keep -restart-pid if we are running tests
4907 if (ARG_FOUND == CheckArgExists("restart-pid") &&
4908 !CheckArg("test-only-automatic-restart-no-wait")) {
4909 // We're not testing and can safely remove it now and read the pid.
4910 const char* restartPidString = nullptr;
4911 CheckArg("restart-pid", &restartPidString, CheckArgFlag::RemoveArg);
4912 // pid should be first parameter following -restart-pid.
4913 uint32_t pid = nsDependentCString(restartPidString).ToInteger(&rv, 10U);
4914 if (NS_SUCCEEDED(rv) && pid > 0) {
4915 printf_stderr(
4916 "*** MaybeWaitForProcessExit: launched pidDWORD = %u ***\n", pid);
4917 RefPtr<nsUpdateProcessor> updater = new nsUpdateProcessor();
4918 if (NS_FAILED(
4919 updater->WaitForProcessExit(pid, MAYBE_WAIT_TIMEOUT_MS))) {
4920 NS_WARNING("Failed to MaybeWaitForProcessExit.");
4922 } else {
4923 NS_WARNING("Failed to parse pid from -restart-pid.");
4927 # endif
4928 Maybe<ShouldNotProcessUpdatesReason> shouldNotProcessUpdatesReason =
4929 ShouldNotProcessUpdates(mDirProvider);
4930 if (shouldNotProcessUpdatesReason.isNothing()) {
4931 // Check for and process any available updates
4932 nsCOMPtr<nsIFile> updRoot;
4933 bool persistent;
4934 rv = mDirProvider.GetFile(XRE_UPDATE_ROOT_DIR, &persistent,
4935 getter_AddRefs(updRoot));
4936 // XRE_UPDATE_ROOT_DIR may fail. Fallback to appDir if failed
4937 if (NS_FAILED(rv)) {
4938 updRoot = mDirProvider.GetAppDir();
4941 // If the MOZ_TEST_PROCESS_UPDATES environment variable already exists, then
4942 // we are being called from the callback application.
4943 if (EnvHasValue("MOZ_TEST_PROCESS_UPDATES")) {
4944 // If the caller has asked us to log our arguments, do so. This is used
4945 // to make sure that the maintenance service successfully launches the
4946 // callback application.
4947 const char* logFile = nullptr;
4948 if (ARG_FOUND == CheckArg("dump-args", &logFile)) {
4949 FILE* logFP = fopen(logFile, "wb");
4950 if (logFP) {
4951 for (int i = 1; i < gRestartArgc; ++i) {
4952 fprintf(logFP, "%s\n", gRestartArgv[i]);
4954 fclose(logFP);
4957 *aExitFlag = true;
4958 return 0;
4961 // Support for processing an update and exiting. The
4962 // MOZ_TEST_PROCESS_UPDATES environment variable will be part of the
4963 // updater's environment and the application that is relaunched by the
4964 // updater. When the application is relaunched by the updater it will be
4965 // removed below and the application will exit.
4966 if (CheckArg("test-process-updates")) {
4967 SaveToEnv("MOZ_TEST_PROCESS_UPDATES=1");
4969 nsCOMPtr<nsIFile> exeFile, exeDir;
4970 rv = mDirProvider.GetFile(XRE_EXECUTABLE_FILE, &persistent,
4971 getter_AddRefs(exeFile));
4972 NS_ENSURE_SUCCESS(rv, 1);
4973 rv = exeFile->GetParent(getter_AddRefs(exeDir));
4974 NS_ENSURE_SUCCESS(rv, 1);
4975 ProcessUpdates(mDirProvider.GetGREDir(), exeDir, updRoot, gRestartArgc,
4976 gRestartArgv, mAppData->version);
4977 if (EnvHasValue("MOZ_TEST_PROCESS_UPDATES")) {
4978 SaveToEnv("MOZ_TEST_PROCESS_UPDATES=");
4979 *aExitFlag = true;
4980 return 0;
4982 } else {
4983 if (CheckArg("test-process-updates") ||
4984 EnvHasValue("MOZ_TEST_PROCESS_UPDATES")) {
4985 // Support for testing *not* processing an update. The launched process
4986 // can witness this environment variable and conclude that its runtime
4987 // environment resulted in not processing updates.
4989 SaveToEnv(nsPrintfCString(
4990 "MOZ_TEST_PROCESS_UPDATES=ShouldNotProcessUpdates(): %s",
4991 ShouldNotProcessUpdatesReasonAsString(
4992 shouldNotProcessUpdatesReason.value()))
4993 .get());
4996 #endif
4998 // We now know there is no existing instance using the selected profile. If
4999 // the profile wasn't selected by specific command line arguments and the
5000 // user has chosen to show the profile manager on startup then do that.
5001 if (wasDefaultSelection) {
5002 bool useSelectedProfile;
5003 rv = mProfileSvc->GetStartWithLastProfile(&useSelectedProfile);
5004 NS_ENSURE_SUCCESS(rv, 1);
5006 if (!useSelectedProfile) {
5007 rv = ShowProfileManager(mProfileSvc, mNativeApp);
5008 if (rv == NS_ERROR_LAUNCHED_CHILD_PROCESS || rv == NS_ERROR_ABORT) {
5009 *aExitFlag = true;
5010 return 0;
5012 if (NS_FAILED(rv)) {
5013 return 1;
5018 // We always want to lock the profile even if we're actually going to reset
5019 // it later.
5020 rv = LockProfile(mNativeApp, mProfD, mProfLD, profile,
5021 getter_AddRefs(mProfileLock));
5022 if (rv == NS_ERROR_LAUNCHED_CHILD_PROCESS || rv == NS_ERROR_ABORT) {
5023 *aExitFlag = true;
5024 return 0;
5025 } else if (NS_FAILED(rv)) {
5026 return 1;
5029 if (gDoProfileReset) {
5030 if (EnvHasValue("MOZ_RESET_PROFILE_RESTART")) {
5031 SaveToEnv("MOZ_RESET_PROFILE_RESTART=");
5032 // We only want to restore the previous session if the profile refresh was
5033 // triggered by user. And if it was a user-triggered profile refresh
5034 // through, say, the safeMode dialog or the troubleshooting page, the
5035 // MOZ_RESET_PROFILE_RESTART env variable would be set. Hence we set
5036 // MOZ_RESET_PROFILE_MIGRATE_SESSION here so that Firefox profile migrator
5037 // would migrate old session data later.
5038 SaveToEnv("MOZ_RESET_PROFILE_MIGRATE_SESSION=1");
5040 // Unlock the source profile.
5041 mProfileLock->Unlock();
5043 // If we're resetting a profile, create a new one and use it to startup.
5044 gResetOldProfile = profile;
5045 rv = mProfileSvc->CreateResetProfile(getter_AddRefs(profile));
5046 if (NS_SUCCEEDED(rv)) {
5047 rv = profile->GetRootDir(getter_AddRefs(mProfD));
5048 NS_ENSURE_SUCCESS(rv, 1);
5049 SaveFileToEnv("XRE_PROFILE_PATH", mProfD);
5051 rv = profile->GetLocalDir(getter_AddRefs(mProfLD));
5052 NS_ENSURE_SUCCESS(rv, 1);
5053 SaveFileToEnv("XRE_PROFILE_LOCAL_PATH", mProfLD);
5055 // Lock the new profile
5056 rv = LockProfile(mNativeApp, mProfD, mProfLD, profile,
5057 getter_AddRefs(mProfileLock));
5058 if (rv == NS_ERROR_LAUNCHED_CHILD_PROCESS || rv == NS_ERROR_ABORT) {
5059 *aExitFlag = true;
5060 return 0;
5061 } else if (NS_FAILED(rv)) {
5062 return 1;
5064 } else {
5065 NS_WARNING("Profile reset failed.");
5066 return 1;
5070 gProfileLock = mProfileLock;
5072 nsAutoCString version;
5073 BuildVersion(version);
5075 #ifdef TARGET_OS_ABI
5076 constexpr auto osABI = nsLiteralCString{TARGET_OS_ABI};
5077 #else
5078 // No TARGET_XPCOM_ABI, but at least the OS is known
5079 constexpr auto osABI = nsLiteralCString{OS_TARGET "_UNKNOWN"};
5080 #endif
5082 // Check for version compatibility with the last version of the app this
5083 // profile was started with. The format of the version stamp is defined
5084 // by the BuildVersion function.
5085 // Also check to see if something has happened to invalidate our
5086 // fastload caches, like an app upgrade.
5088 // If we see .purgecaches, that means someone did a make.
5089 // Re-register components to catch potential changes.
5090 nsCOMPtr<nsIFile> flagFile;
5091 if (mAppData->directory) {
5092 Unused << mAppData->directory->Clone(getter_AddRefs(flagFile));
5094 if (flagFile) {
5095 flagFile->AppendNative(FILE_INVALIDATE_CACHES);
5098 bool cachesOK;
5099 bool isDowngrade;
5100 nsCString lastVersion;
5101 bool versionOK = CheckCompatibility(
5102 mProfD, version, osABI, mDirProvider.GetGREDir(), mAppData->directory,
5103 flagFile, &cachesOK, &isDowngrade, lastVersion);
5105 MOZ_RELEASE_ASSERT(!cachesOK || lastVersion.Equals(version),
5106 "Caches cannot be good if the version has changed.");
5108 #ifdef MOZ_BLOCK_PROFILE_DOWNGRADE
5109 // The argument check must come first so the argument is always removed from
5110 // the command line regardless of whether this is a downgrade or not.
5111 if (!CheckArg("allow-downgrade") && isDowngrade &&
5112 !EnvHasValue("MOZ_ALLOW_DOWNGRADE")) {
5113 rv = CheckDowngrade(mProfD, mNativeApp, mProfileSvc, lastVersion);
5114 if (rv == NS_ERROR_LAUNCHED_CHILD_PROCESS || rv == NS_ERROR_ABORT) {
5115 *aExitFlag = true;
5116 return 0;
5119 #endif
5121 rv = mDirProvider.SetProfile(mProfD, mProfLD);
5122 NS_ENSURE_SUCCESS(rv, 1);
5124 //////////////////////// NOW WE HAVE A PROFILE ////////////////////////
5126 mozilla::Telemetry::SetProfileDir(mProfD);
5128 if (mAppData->flags & NS_XRE_ENABLE_CRASH_REPORTER) {
5129 MakeOrSetMinidumpPath(mProfD);
5132 CrashReporter::SetProfileDirectory(mProfD);
5134 #ifdef MOZ_ASAN_REPORTER
5135 // In ASan reporter builds, we need to set ASan's log_path as early as
5136 // possible, so it dumps its errors into files there instead of using
5137 // the default stderr location. Since this is crucial for ASan reporter
5138 // to work at all (and we don't want people to use a non-functional
5139 // ASan reporter build), all failures while setting log_path are fatal.
5140 setASanReporterPath(mProfD);
5142 // Export to env for child processes
5143 SaveFileToEnv("ASAN_REPORTER_PATH", mProfD);
5144 #endif
5146 bool lastStartupWasCrash = CheckLastStartupWasCrash();
5148 CrashReporter::AnnotateCrashReport(
5149 CrashReporter::Annotation::LastStartupWasCrash, lastStartupWasCrash);
5151 if (CheckArg("purgecaches") || PR_GetEnv("MOZ_PURGE_CACHES") ||
5152 lastStartupWasCrash || gSafeMode) {
5153 cachesOK = false;
5156 CrashReporter::AnnotateCrashReport(
5157 CrashReporter::Annotation::StartupCacheValid, cachesOK && versionOK);
5159 // Every time a profile is loaded by a build with a different version,
5160 // it updates the compatibility.ini file saying what version last wrote
5161 // the fastload caches. On subsequent launches if the version matches,
5162 // there is no need for re-registration. If the user loads the same
5163 // profile in different builds the component registry must be
5164 // re-generated to prevent mysterious component loading failures.
5166 bool startupCacheValid = true;
5168 if (!cachesOK || !versionOK) {
5169 QuotaManager::InvalidateQuotaCache();
5171 startupCacheValid = RemoveComponentRegistries(mProfD, mProfLD, false);
5173 // Rewrite compatibility.ini to match the current build. The next run
5174 // should attempt to invalidate the caches if either this run is safe mode
5175 // or the attempt to invalidate the caches this time failed.
5176 WriteVersion(mProfD, version, osABI, mDirProvider.GetGREDir(),
5177 mAppData->directory, gSafeMode || !startupCacheValid);
5180 if (!startupCacheValid) StartupCache::IgnoreDiskCache();
5182 if (flagFile) {
5183 flagFile->Remove(true);
5186 // Flush any pending page load events.
5187 mozilla::glean_pings::Pageload.Submit("startup"_ns);
5189 if (!isBackgroundTaskMode) {
5190 #ifdef USE_GLX_TEST
5191 GfxInfo::FireGLXTestProcess();
5192 #endif
5193 #ifdef MOZ_WAYLAND
5194 // Make sure we have wayland connection for main thread.
5195 // It's used as template to create display connections
5196 // for different threads.
5197 if (IsWaylandEnabled()) {
5198 MOZ_UNUSED(WaylandDisplayGet());
5200 #endif
5201 #ifdef MOZ_WIDGET_GTK
5202 nsAppShell::InstallTermSignalHandler();
5203 #endif
5206 return 0;
5209 #if defined(MOZ_SANDBOX)
5210 void AddSandboxAnnotations() {
5212 // Include the sandbox content level, regardless of platform
5213 int level = GetEffectiveContentSandboxLevel();
5215 nsAutoCString levelString;
5216 levelString.AppendInt(level);
5218 CrashReporter::AnnotateCrashReport(
5219 CrashReporter::Annotation::ContentSandboxLevel, levelString);
5223 int level = GetEffectiveGpuSandboxLevel();
5225 nsAutoCString levelString;
5226 levelString.AppendInt(level);
5228 CrashReporter::AnnotateCrashReport(
5229 CrashReporter::Annotation::GpuSandboxLevel, levelString);
5232 // Include whether or not this instance is capable of content sandboxing
5233 bool sandboxCapable = false;
5235 # if defined(XP_WIN)
5236 // All supported Windows versions support some level of content sandboxing
5237 sandboxCapable = true;
5238 # elif defined(XP_MACOSX)
5239 // All supported OS X versions are capable
5240 sandboxCapable = true;
5241 # elif defined(XP_LINUX)
5242 sandboxCapable = SandboxInfo::Get().CanSandboxContent();
5243 # elif defined(__OpenBSD__)
5244 sandboxCapable = true;
5245 StartOpenBSDSandbox(GeckoProcessType_Default);
5246 # endif
5248 CrashReporter::AnnotateCrashReport(
5249 CrashReporter::Annotation::ContentSandboxCapable, sandboxCapable);
5251 #endif /* MOZ_SANDBOX */
5254 * XRE_mainRun - Command line startup, profile migration, and
5255 * the calling of appStartup->Run().
5257 nsresult XREMain::XRE_mainRun() {
5258 nsresult rv = NS_OK;
5259 NS_ASSERTION(mScopedXPCOM, "Scoped xpcom not initialized.");
5261 #if defined(XP_WIN)
5262 RefPtr<mozilla::DllServices> dllServices(mozilla::DllServices::Get());
5263 dllServices->StartUntrustedModulesProcessor(false);
5264 auto dllServicesDisable =
5265 MakeScopeExit([&dllServices]() { dllServices->DisableFull(); });
5267 mozilla::mscom::InitProfilerMarkers();
5268 #endif // defined(XP_WIN)
5270 // We need the appStartup pointer to span multiple scopes, so we declare
5271 // it here.
5272 nsCOMPtr<nsIAppStartup> appStartup;
5273 // Ditto with the command line.
5274 nsCOMPtr<nsICommandLineRunner> cmdLine;
5277 #ifdef XP_MACOSX
5278 // In this scope, create an autorelease pool that will leave scope with
5279 // it just before entering our event loop.
5280 mozilla::MacAutoreleasePool pool;
5281 #endif
5283 rv = mScopedXPCOM->SetWindowCreator(mNativeApp);
5284 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
5286 // tell the crash reporter to also send the release channel
5287 nsCOMPtr<nsIPrefService> prefs =
5288 do_GetService("@mozilla.org/preferences-service;1", &rv);
5289 if (NS_SUCCEEDED(rv)) {
5290 nsCOMPtr<nsIPrefBranch> defaultPrefBranch;
5291 rv = prefs->GetDefaultBranch(nullptr, getter_AddRefs(defaultPrefBranch));
5293 if (NS_SUCCEEDED(rv)) {
5294 nsAutoCString sval;
5295 rv = defaultPrefBranch->GetCharPref("app.update.channel", sval);
5296 if (NS_SUCCEEDED(rv)) {
5297 CrashReporter::AnnotateCrashReport(
5298 CrashReporter::Annotation::ReleaseChannel, sval);
5302 // Needs to be set after xpcom initialization.
5303 bool includeContextHeap = Preferences::GetBool(
5304 "toolkit.crashreporter.include_context_heap", false);
5305 CrashReporter::SetIncludeContextHeap(includeContextHeap);
5307 #if defined(XP_LINUX) && !defined(ANDROID)
5308 PR_CreateThread(PR_USER_THREAD, AnnotateLSBRelease, 0, PR_PRIORITY_LOW,
5309 PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD, 0);
5310 #endif
5312 if (mStartOffline) {
5313 nsCOMPtr<nsIIOService> io(
5314 do_GetService("@mozilla.org/network/io-service;1"));
5315 NS_ENSURE_TRUE(io, NS_ERROR_FAILURE);
5316 io->SetManageOfflineStatus(false);
5317 io->SetOffline(true);
5320 #ifdef XP_WIN
5321 mozilla::DllPrefetchExperimentRegistryInfo prefetchRegInfo;
5322 mozilla::AlteredDllPrefetchMode dllPrefetchMode =
5323 prefetchRegInfo.GetAlteredDllPrefetchMode();
5325 if (!PR_GetEnv("XRE_NO_DLL_READAHEAD") &&
5326 dllPrefetchMode != mozilla::AlteredDllPrefetchMode::NoPrefetch) {
5327 nsCOMPtr<nsIFile> greDir = mDirProvider.GetGREDir();
5328 nsAutoString path;
5329 rv = greDir->GetPath(path);
5330 if (NS_SUCCEEDED(rv)) {
5331 PRThread* readAheadThread;
5332 wchar_t* pathRaw;
5334 // We use the presence of a path argument inside the thread to determine
5335 // which list of Dlls to use. The old list does not need access to the
5336 // GRE dir, so the path argument is set to a null pointer.
5337 if (dllPrefetchMode ==
5338 mozilla::AlteredDllPrefetchMode::OptimizedPrefetch) {
5339 pathRaw = new wchar_t[MAX_PATH];
5340 wcscpy_s(pathRaw, MAX_PATH, path.get());
5341 } else {
5342 pathRaw = nullptr;
5344 readAheadThread = PR_CreateThread(
5345 PR_USER_THREAD, ReadAheadDlls_ThreadStart, (void*)pathRaw,
5346 PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD, 0);
5347 if (readAheadThread == NULL) {
5348 delete[] pathRaw;
5352 #endif
5354 if (gDoMigration) {
5355 nsCOMPtr<nsIFile> file;
5356 mDirProvider.GetAppDir()->Clone(getter_AddRefs(file));
5357 file->AppendNative("override.ini"_ns);
5358 nsINIParser parser;
5359 nsresult rv = parser.Init(file);
5360 // if override.ini doesn't exist, also check for distribution.ini
5361 if (NS_FAILED(rv)) {
5362 bool persistent;
5363 mDirProvider.GetFile(XRE_APP_DISTRIBUTION_DIR, &persistent,
5364 getter_AddRefs(file));
5365 file->AppendNative("distribution.ini"_ns);
5366 rv = parser.Init(file);
5368 if (NS_SUCCEEDED(rv)) {
5369 nsAutoCString buf;
5370 rv = parser.GetString("XRE", "EnableProfileMigrator", buf);
5371 if (NS_SUCCEEDED(rv)) {
5372 if (buf[0] == '0' || buf[0] == 'f' || buf[0] == 'F') {
5373 gDoMigration = false;
5379 // We'd like to initialize the JSContext *after* reading the user prefs.
5380 // Unfortunately that's not possible if we have to do profile migration
5381 // because that requires us to execute JS before reading user prefs.
5382 // Restarting the browser after profile migration would fix this. See
5383 // bug 1592523.
5384 bool initializedJSContext = false;
5387 // Profile Migration
5388 if (mAppData->flags & NS_XRE_ENABLE_PROFILE_MIGRATOR && gDoMigration) {
5389 gDoMigration = false;
5391 xpc::InitializeJSContext();
5392 initializedJSContext = true;
5394 nsCOMPtr<nsIProfileMigrator> pm(
5395 do_CreateInstance(NS_PROFILEMIGRATOR_CONTRACTID));
5396 if (pm) {
5397 nsAutoCString aKey;
5398 nsAutoCString aName;
5399 if (gDoProfileReset) {
5400 // Automatically migrate from the current application if we just
5401 // reset the profile.
5402 aKey = MOZ_APP_NAME;
5403 gResetOldProfile->GetName(aName);
5405 #ifdef XP_MACOSX
5406 // Necessary for migration wizard to be accessible.
5407 InitializeMacApp();
5408 #endif
5409 pm->Migrate(&mDirProvider, aKey, aName);
5413 if (gDoProfileReset) {
5414 if (!initializedJSContext) {
5415 xpc::InitializeJSContext();
5416 initializedJSContext = true;
5419 nsresult backupCreated =
5420 ProfileResetCleanup(mProfileSvc, gResetOldProfile);
5421 if (NS_FAILED(backupCreated)) {
5422 NS_WARNING("Could not cleanup the profile that was reset");
5427 // Initialize user preferences before notifying startup observers so they're
5428 // ready in time for early consumers, such as the component loader.
5429 mDirProvider.InitializeUserPrefs();
5431 // Now that all (user) prefs have been loaded we can initialize the main
5432 // thread's JSContext.
5433 if (!initializedJSContext) {
5434 xpc::InitializeJSContext();
5437 // Finally, now that JS has been initialized, we can finish pref loading.
5438 // This needs to happen after JS and XPConnect initialization because
5439 // AutoConfig files require JS execution. Note that this means AutoConfig
5440 // files can't override JS engine start-up prefs.
5441 mDirProvider.FinishInitializingUserPrefs();
5443 #if defined(MOZ_SANDBOX) && defined(XP_WIN)
5444 // Now that we have preferences and the directory provider, we can
5445 // finish initializing SandboxBroker. This must happen before the GFX
5446 // platform is initialized (which will launch the GPU process), which
5447 // occurs when the "app-startup" category is started up below
5449 // After this completes, we are ready to launch sandboxed processes
5450 mozilla::SandboxBroker::GeckoDependentInitialize();
5451 #endif
5453 nsCOMPtr<nsIFile> workingDir;
5454 rv = NS_GetSpecialDirectory(NS_OS_CURRENT_WORKING_DIR,
5455 getter_AddRefs(workingDir));
5456 if (NS_FAILED(rv)) {
5457 // No working dir? This can happen if it gets deleted before we start.
5458 workingDir = nullptr;
5461 cmdLine = new nsCommandLine();
5463 rv = cmdLine->Init(gArgc, gArgv, workingDir,
5464 nsICommandLine::STATE_INITIAL_LAUNCH);
5465 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
5467 // "app-startup" is the name of both the category and the event
5468 NS_CreateServicesFromCategory("app-startup", cmdLine, "app-startup",
5469 nullptr);
5471 appStartup = components::AppStartup::Service();
5472 NS_ENSURE_TRUE(appStartup, NS_ERROR_FAILURE);
5474 mDirProvider.DoStartup();
5476 #ifdef XP_WIN
5477 // It needs to be called on the main thread because it has to use
5478 // nsObserverService.
5479 EnsureWin32kInitialized();
5480 #endif
5482 // As FilePreferences need the profile directory, we must initialize right
5483 // here.
5484 mozilla::FilePreferences::InitDirectoriesAllowlist();
5485 mozilla::FilePreferences::InitPrefs();
5487 nsCString userAgentLocale;
5488 LocaleService::GetInstance()->GetAppLocaleAsBCP47(userAgentLocale);
5489 CrashReporter::AnnotateCrashReport(
5490 CrashReporter::Annotation::useragent_locale, userAgentLocale);
5492 if (!AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed)) {
5493 /* Special-case services that need early access to the command
5494 line. */
5495 nsCOMPtr<nsIObserverService> obsService =
5496 mozilla::services::GetObserverService();
5497 if (obsService) {
5498 obsService->NotifyObservers(cmdLine, "command-line-startup", nullptr);
5502 #ifdef XP_WIN
5503 // Hack to sync up the various environment storages. XUL_APP_FILE is special
5504 // in that it comes from a different CRT (firefox.exe's static-linked copy).
5505 // Ugly details in http://bugzil.la/1175039#c27
5506 char appFile[MAX_PATH];
5507 if (GetEnvironmentVariableA("XUL_APP_FILE", appFile, sizeof(appFile))) {
5508 SmprintfPointer saved = mozilla::Smprintf("XUL_APP_FILE=%s", appFile);
5509 // We intentionally leak the string here since it is required by
5510 // PR_SetEnv.
5511 PR_SetEnv(saved.release());
5513 #endif
5515 mozilla::AppShutdown::SaveEnvVarsForPotentialRestart();
5517 // clear out any environment variables which may have been set
5518 // during the relaunch process now that we know we won't be relaunching.
5519 SaveToEnv("XRE_PROFILE_PATH=");
5520 SaveToEnv("XRE_PROFILE_LOCAL_PATH=");
5521 SaveToEnv("XRE_START_OFFLINE=");
5522 SaveToEnv("XUL_APP_FILE=");
5523 SaveToEnv("XRE_BINARY_PATH=");
5524 SaveToEnv("XRE_RESTARTED_BY_PROFILE_MANAGER=");
5526 if (!AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed)) {
5527 // Don't create the hidden window during startup on
5528 // platforms that don't always need it.
5529 #ifdef XP_MACOSX
5530 bool lazyHiddenWindow = false;
5531 #else
5532 bool lazyHiddenWindow = true;
5533 #endif
5535 #ifdef MOZ_BACKGROUNDTASKS
5536 if (BackgroundTasks::IsBackgroundTaskMode()) {
5537 // Background tasks aren't going to load a chrome XUL document.
5538 lazyHiddenWindow = true;
5540 #endif
5542 if (!lazyHiddenWindow) {
5543 rv = appStartup->CreateHiddenWindow();
5544 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
5547 #ifdef XP_WIN
5548 Preferences::RegisterCallbackAndCall(
5549 RegisterApplicationRestartChanged,
5550 PREF_WIN_REGISTER_APPLICATION_RESTART);
5551 SetupAlteredPrefetchPref();
5552 SetupSkeletonUIPrefs();
5553 # if defined(MOZ_LAUNCHER_PROCESS)
5554 SetupLauncherProcessPref();
5555 # endif // defined(MOZ_LAUNCHER_PROCESS)
5556 # if defined(MOZ_DEFAULT_BROWSER_AGENT)
5557 # if defined(MOZ_BACKGROUNDTASKS)
5558 // The backgroundtask profile is not a browsing profile, let alone the new
5559 // default profile, so don't mirror its properties into the registry.
5560 if (!BackgroundTasks::IsBackgroundTaskMode())
5561 # endif // defined(MOZ_BACKGROUNDTASKS)
5563 Preferences::RegisterCallbackAndCall(
5564 &OnDefaultAgentTelemetryPrefChanged,
5565 kPrefHealthReportUploadEnabled);
5566 Preferences::RegisterCallbackAndCall(
5567 &OnDefaultAgentTelemetryPrefChanged, kPrefDefaultAgentEnabled);
5569 Preferences::RegisterCallbackAndCall(
5570 &OnDefaultAgentRemoteSettingsPrefChanged,
5571 kPrefServicesSettingsServer);
5572 Preferences::RegisterCallbackAndCall(
5573 &OnDefaultAgentRemoteSettingsPrefChanged,
5574 kPrefSecurityContentSignatureRootHash);
5576 Preferences::RegisterCallbackAndCall(
5577 &OnSetDefaultBrowserUserChoicePrefChanged,
5578 kPrefSetDefaultBrowserUserChoicePref);
5580 SetDefaultAgentLastRunTime();
5582 # endif // defined(MOZ_DEFAULT_BROWSER_AGENT)
5583 #endif
5585 #if defined(MOZ_WIDGET_GTK)
5586 // Clear the environment variables so they won't be inherited by child
5587 // processes and confuse things.
5588 for (const auto& name : kStartupTokenNames) {
5589 g_unsetenv(name.get());
5591 #endif
5593 #ifdef XP_MACOSX
5594 InitializeMacApp();
5596 // we re-initialize the command-line service and do appleevents munging
5597 // after we are sure that we're not restarting
5598 cmdLine = new nsCommandLine();
5600 char** tempArgv = static_cast<char**>(malloc(gArgc * sizeof(char*)));
5601 for (int i = 0; i < gArgc; i++) {
5602 tempArgv[i] = strdup(gArgv[i]);
5604 CommandLineServiceMac::SetupMacCommandLine(gArgc, tempArgv, false);
5605 rv = cmdLine->Init(gArgc, tempArgv, workingDir,
5606 nsICommandLine::STATE_INITIAL_LAUNCH);
5607 free(tempArgv);
5608 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
5610 # ifdef MOZILLA_OFFICIAL
5611 // Check if we're running from a DMG or an app translocated location and
5612 // allow the user to install to the Applications directory.
5613 if (MacRunFromDmgUtils::MaybeInstallAndRelaunch()) {
5614 bool userAllowedQuit = true;
5615 appStartup->Quit(nsIAppStartup::eForceQuit, 0, &userAllowedQuit);
5617 # endif
5618 #endif
5620 nsCOMPtr<nsIObserverService> obsService =
5621 mozilla::services::GetObserverService();
5622 if (obsService)
5623 obsService->NotifyObservers(nullptr, "final-ui-startup", nullptr);
5625 (void)appStartup->DoneStartingUp();
5627 CrashReporter::AnnotateCrashReport(
5628 CrashReporter::Annotation::StartupCrash, false);
5630 AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed);
5633 if (!AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed)) {
5634 rv = cmdLine->Run();
5635 NS_ENSURE_SUCCESS_LOG(rv, NS_ERROR_FAILURE);
5638 if (!AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed)) {
5639 #if defined(MOZ_HAS_REMOTE)
5640 // if we have X remote support, start listening for requests on the
5641 // proxy window.
5642 if (mRemoteService && !mDisableRemoteServer) {
5643 mRemoteService->StartupServer();
5644 mRemoteService->UnlockStartup();
5645 gRemoteService = nullptr;
5647 #endif /* MOZ_WIDGET_GTK */
5649 mNativeApp->Enable();
5652 #ifdef MOZ_INSTRUMENT_EVENT_LOOP
5653 if (PR_GetEnv("MOZ_INSTRUMENT_EVENT_LOOP")) {
5654 bool logToConsole = true;
5655 mozilla::InitEventTracing(logToConsole);
5657 #endif /* MOZ_INSTRUMENT_EVENT_LOOP */
5659 // Send Telemetry about Gecko version and buildid
5660 mozilla::glean::gecko::version.Set(nsDependentCString(gAppData->version));
5661 mozilla::glean::gecko::build_id.Set(nsDependentCString(gAppData->buildID));
5663 #if defined(MOZ_SANDBOX) && defined(XP_LINUX)
5664 // If we're on Linux, we now have information about the OS capabilities
5665 // available to us.
5666 SandboxInfo sandboxInfo = SandboxInfo::Get();
5667 Telemetry::Accumulate(Telemetry::SANDBOX_HAS_SECCOMP_BPF,
5668 sandboxInfo.Test(SandboxInfo::kHasSeccompBPF));
5669 Telemetry::Accumulate(Telemetry::SANDBOX_HAS_SECCOMP_TSYNC,
5670 sandboxInfo.Test(SandboxInfo::kHasSeccompTSync));
5671 Telemetry::Accumulate(
5672 Telemetry::SANDBOX_HAS_USER_NAMESPACES_PRIVILEGED,
5673 sandboxInfo.Test(SandboxInfo::kHasPrivilegedUserNamespaces));
5674 Telemetry::Accumulate(Telemetry::SANDBOX_HAS_USER_NAMESPACES,
5675 sandboxInfo.Test(SandboxInfo::kHasUserNamespaces));
5676 Telemetry::Accumulate(Telemetry::SANDBOX_CONTENT_ENABLED,
5677 sandboxInfo.Test(SandboxInfo::kEnabledForContent));
5678 Telemetry::Accumulate(Telemetry::SANDBOX_MEDIA_ENABLED,
5679 sandboxInfo.Test(SandboxInfo::kEnabledForMedia));
5680 nsAutoCString flagsString;
5681 flagsString.AppendInt(sandboxInfo.AsInteger());
5683 CrashReporter::AnnotateCrashReport(
5684 CrashReporter::Annotation::ContentSandboxCapabilities, flagsString);
5685 #endif /* MOZ_SANDBOX && XP_LINUX */
5687 #if defined(XP_WIN)
5688 LauncherResult<bool> isAdminWithoutUac = IsAdminWithoutUac();
5689 if (isAdminWithoutUac.isOk()) {
5690 Telemetry::ScalarSet(
5691 Telemetry::ScalarID::OS_ENVIRONMENT_IS_ADMIN_WITHOUT_UAC,
5692 isAdminWithoutUac.unwrap());
5694 #endif /* XP_WIN */
5696 #if defined(MOZ_SANDBOX)
5697 AddSandboxAnnotations();
5698 #endif /* MOZ_SANDBOX */
5700 mProfileSvc->CompleteStartup();
5703 #ifdef MOZ_BACKGROUNDTASKS
5704 if (BackgroundTasks::IsBackgroundTaskMode()) {
5705 // In background task mode, we don't fire various delayed initialization
5706 // notifications, which in the regular browser is how startup crash tracking
5707 // is marked as finished. Here, getting this far means we don't have a
5708 // startup crash.
5709 rv = appStartup->TrackStartupCrashEnd();
5710 NS_ENSURE_SUCCESS(rv, rv);
5712 // We never open a window, but don't want to exit immediately.
5713 rv = appStartup->EnterLastWindowClosingSurvivalArea();
5714 NS_ENSURE_SUCCESS(rv, rv);
5716 // Avoid some small differences in initialization order across platforms.
5717 nsCOMPtr<nsIPowerManagerService> powerManagerService =
5718 do_GetService(POWERMANAGERSERVICE_CONTRACTID);
5719 nsCOMPtr<nsIStringBundleService> stringBundleService =
5720 do_GetService(NS_STRINGBUNDLE_CONTRACTID);
5722 rv = BackgroundTasks::RunBackgroundTask(cmdLine);
5723 NS_ENSURE_SUCCESS(rv, rv);
5725 #endif
5728 rv = appStartup->Run();
5729 if (NS_FAILED(rv)) {
5730 NS_ERROR("failed to run appstartup");
5731 gLogConsoleErrors = true;
5735 return rv;
5738 #if defined(MOZ_WIDGET_ANDROID)
5739 static already_AddRefed<nsIFile> GreOmniPath(int argc, char** argv) {
5740 nsresult rv;
5742 const char* path = nullptr;
5743 ArgResult ar = CheckArg(argc, argv, "greomni", &path, CheckArgFlag::None);
5744 if (ar == ARG_BAD) {
5745 PR_fprintf(PR_STDERR,
5746 "Error: argument --greomni requires a path argument\n");
5747 return nullptr;
5750 if (!path) return nullptr;
5752 nsCOMPtr<nsIFile> greOmni;
5753 rv = XRE_GetFileFromPath(path, getter_AddRefs(greOmni));
5754 if (NS_FAILED(rv)) {
5755 PR_fprintf(PR_STDERR, "Error: argument --greomni requires a valid path\n");
5756 return nullptr;
5759 return greOmni.forget();
5761 #endif
5764 * XRE_main - A class based main entry point used by most platforms.
5765 * Note that on OSX, aAppData->xreDirectory will point to
5766 * .app/Contents/Resources.
5768 int XREMain::XRE_main(int argc, char* argv[], const BootstrapConfig& aConfig) {
5769 gArgc = argc;
5770 gArgv = argv;
5772 ScopedLogging log;
5774 mozilla::LogModule::Init(gArgc, gArgv);
5776 #ifndef XP_LINUX
5777 NS_SetCurrentThreadName("MainThread");
5778 #endif
5780 AUTO_BASE_PROFILER_LABEL("XREMain::XRE_main (around Gecko Profiler)", OTHER);
5781 AUTO_PROFILER_INIT;
5782 AUTO_PROFILER_LABEL("XREMain::XRE_main", OTHER);
5784 #ifdef XP_MACOSX
5785 // We call this early because it will kick off a background-thread task
5786 // to register the fonts, and we'd like it to have a chance to complete
5787 // before gfxPlatform initialization actually requires it.
5788 gfxPlatformMac::RegisterSupplementalFonts();
5789 #endif
5791 #ifdef MOZ_CODE_COVERAGE
5792 CodeCoverageHandler::Init();
5793 #endif
5795 nsresult rv = NS_OK;
5797 if (aConfig.appData) {
5798 mAppData = MakeUnique<XREAppData>(*aConfig.appData);
5799 } else {
5800 MOZ_RELEASE_ASSERT(aConfig.appDataPath);
5801 nsCOMPtr<nsIFile> appini;
5802 rv = XRE_GetFileFromPath(aConfig.appDataPath, getter_AddRefs(appini));
5803 if (NS_FAILED(rv)) {
5804 Output(true, "Error: unrecognized path: %s\n", aConfig.appDataPath);
5805 return 1;
5808 mAppData = MakeUnique<XREAppData>();
5809 rv = XRE_ParseAppData(appini, *mAppData);
5810 if (NS_FAILED(rv)) {
5811 Output(true, "Couldn't read application.ini");
5812 return 1;
5815 appini->GetParent(getter_AddRefs(mAppData->directory));
5818 const char* appRemotingName = getenv("MOZ_APP_REMOTINGNAME");
5819 if (appRemotingName) {
5820 mAppData->remotingName = appRemotingName;
5821 } else if (!mAppData->remotingName) {
5822 mAppData->remotingName = mAppData->name;
5824 // used throughout this file
5825 gAppData = mAppData.get();
5827 nsCOMPtr<nsIFile> binFile;
5828 rv = XRE_GetBinaryPath(getter_AddRefs(binFile));
5829 NS_ENSURE_SUCCESS(rv, 1);
5831 rv = binFile->GetPath(gAbsoluteArgv0Path);
5832 NS_ENSURE_SUCCESS(rv, 1);
5834 if (!mAppData->xreDirectory) {
5835 nsCOMPtr<nsIFile> greDir;
5837 #if defined(MOZ_WIDGET_ANDROID)
5838 greDir = GreOmniPath(argc, argv);
5839 if (!greDir) {
5840 return 2;
5842 #else
5843 rv = binFile->GetParent(getter_AddRefs(greDir));
5844 if (NS_FAILED(rv)) return 2;
5845 #endif
5847 #ifdef XP_MACOSX
5848 nsCOMPtr<nsIFile> parent;
5849 greDir->GetParent(getter_AddRefs(parent));
5850 greDir = parent.forget();
5851 greDir->AppendNative("Resources"_ns);
5852 #endif
5854 mAppData->xreDirectory = greDir;
5857 #if defined(MOZ_WIDGET_ANDROID)
5858 nsCOMPtr<nsIFile> dataDir;
5859 rv = binFile->GetParent(getter_AddRefs(dataDir));
5860 if (NS_FAILED(rv)) return 2;
5862 mAppData->directory = dataDir;
5863 #else
5864 if (aConfig.appData && aConfig.appDataPath) {
5865 mAppData->xreDirectory->Clone(getter_AddRefs(mAppData->directory));
5866 mAppData->directory->AppendNative(nsDependentCString(aConfig.appDataPath));
5868 #endif
5870 if (!mAppData->directory) {
5871 mAppData->directory = mAppData->xreDirectory;
5874 #if defined(XP_WIN)
5875 # if defined(MOZ_SANDBOX)
5876 mAppData->sandboxBrokerServices = aConfig.sandboxBrokerServices;
5877 # endif // defined(MOZ_SANDBOX)
5880 DebugOnly<bool> result = WindowsBCryptInitialization();
5881 MOZ_ASSERT(result);
5884 # if defined(_M_IX86) || defined(_M_X64)
5886 DebugOnly<bool> result = WindowsMsctfInitialization();
5887 MOZ_ASSERT(result);
5889 # endif // _M_IX86 || _M_X64
5891 #endif // defined(XP_WIN)
5893 // Once we unset the exception handler, we lose the ability to properly
5894 // detect hangs -- they show up as crashes. We do this as late as possible.
5895 // In particular, after ProcessRuntime is destroyed on Windows.
5896 auto unsetExceptionHandler = MakeScopeExit([&] {
5897 if (mAppData->flags & NS_XRE_ENABLE_CRASH_REPORTER)
5898 return CrashReporter::UnsetExceptionHandler();
5899 return NS_OK;
5902 mozilla::AutoIOInterposer ioInterposerGuard;
5903 ioInterposerGuard.Init();
5905 #if defined(XP_WIN)
5906 // We should have already done this when we created the skeleton UI. However,
5907 // there is code in here which needs xul in order to work, like EnsureMTA. It
5908 // should be setup that running it again is safe.
5909 mozilla::mscom::ProcessRuntime msCOMRuntime;
5910 #endif
5912 // init
5913 bool exit = false;
5914 int result = XRE_mainInit(&exit);
5915 if (result != 0 || exit) return result;
5917 // If we exit gracefully, remove the startup crash canary file.
5918 auto cleanup = MakeScopeExit([&]() -> nsresult {
5919 if (mProfLD) {
5920 nsCOMPtr<nsIFile> crashFile;
5921 MOZ_TRY_VAR(crashFile, GetIncompleteStartupFile(mProfLD));
5922 crashFile->Remove(false);
5924 return NS_OK;
5927 // startup
5928 result = XRE_mainStartup(&exit);
5929 if (result != 0 || exit) return result;
5931 // Start the real application. We use |aInitJSContext = false| because
5932 // XRE_mainRun wants to initialize the JSContext after reading user prefs.
5934 mScopedXPCOM = MakeUnique<ScopedXPCOMStartup>();
5936 rv = mScopedXPCOM->Initialize(/* aInitJSContext = */ false);
5937 NS_ENSURE_SUCCESS(rv, 1);
5939 // run!
5940 rv = XRE_mainRun();
5942 #ifdef MOZ_X11
5943 XRE_CleanupX11ErrorHandler();
5944 #endif
5946 #ifdef MOZ_INSTRUMENT_EVENT_LOOP
5947 mozilla::ShutdownEventTracing();
5948 #endif
5950 gAbsoluteArgv0Path.Truncate();
5952 #if defined(MOZ_HAS_REMOTE)
5953 // Shut down the remote service. We must do this before calling LaunchChild
5954 // if we're restarting because otherwise the new instance will attempt to
5955 // remote to this instance.
5956 if (mRemoteService && !mDisableRemoteServer) {
5957 mRemoteService->ShutdownServer();
5959 #endif /* MOZ_WIDGET_GTK */
5961 mScopedXPCOM = nullptr;
5963 // unlock the profile after ScopedXPCOMStartup object (xpcom)
5964 // has gone out of scope. see bug #386739 for more details
5965 mProfileLock->Unlock();
5966 gProfileLock = nullptr;
5968 gLastAppVersion.Truncate();
5969 gLastAppBuildID.Truncate();
5971 #ifdef MOZ_WIDGET_GTK
5972 // gdk_display_close also calls gdk_display_manager_set_default_display
5973 // appropriately when necessary.
5974 if (!gfxPlatform::IsHeadless()) {
5975 # ifdef MOZ_WAYLAND
5976 WaylandDisplayRelease();
5977 gWaylandProxy = nullptr;
5978 # endif
5980 #endif
5982 mozilla::AppShutdown::MaybeDoRestart();
5984 XRE_DeinitCommandLine();
5986 if (NS_FAILED(rv)) {
5987 return 1;
5989 return mozilla::AppShutdown::GetExitCode();
5992 void XRE_StopLateWriteChecks(void) { mozilla::StopLateWriteChecks(); }
5994 int XRE_main(int argc, char* argv[], const BootstrapConfig& aConfig) {
5995 XREMain main;
5997 int result = main.XRE_main(argc, argv, aConfig);
5998 mozilla::RecordShutdownEndTimeStamp();
5999 #ifdef MOZ_BACKGROUNDTASKS
6000 // This is well after the profile has been unlocked, so it's okay if this does
6001 // delete this background task's temporary profile.
6002 mozilla::BackgroundTasks::Shutdown();
6003 #endif
6004 return result;
6007 nsresult XRE_InitCommandLine(int aArgc, char* aArgv[]) {
6008 nsresult rv = NS_OK;
6010 #if defined(XP_WIN)
6011 CommandLine::Init(aArgc, aArgv);
6012 #else
6014 // these leak on error, but that's OK: we'll just exit()
6015 char** canonArgs = new char*[aArgc];
6017 // get the canonical version of the binary's path
6018 nsCOMPtr<nsIFile> binFile;
6019 rv = XRE_GetBinaryPath(getter_AddRefs(binFile));
6020 if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
6022 nsAutoCString canonBinPath;
6023 rv = binFile->GetNativePath(canonBinPath);
6024 if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
6026 canonArgs[0] = strdup(canonBinPath.get());
6028 for (int i = 1; i < aArgc; ++i) {
6029 if (aArgv[i]) {
6030 canonArgs[i] = strdup(aArgv[i]);
6034 NS_ASSERTION(!CommandLine::IsInitialized(), "Bad news!");
6035 CommandLine::Init(aArgc, canonArgs);
6037 for (int i = 0; i < aArgc; ++i) free(canonArgs[i]);
6038 delete[] canonArgs;
6039 #endif
6041 #if defined(MOZ_WIDGET_ANDROID)
6042 // gAppData is non-null iff this is the parent process. Otherwise,
6043 // the `-greomni`/`-appomni` flags are cross-platform and handled in
6044 // ContentProcess::Init.
6045 if (gAppData) {
6046 nsCOMPtr<nsIFile> greOmni = gAppData->xreDirectory;
6047 if (!greOmni) {
6048 return NS_ERROR_FAILURE;
6050 mozilla::Omnijar::Init(greOmni, greOmni);
6052 #endif
6054 return rv;
6057 nsresult XRE_DeinitCommandLine() {
6058 nsresult rv = NS_OK;
6060 CommandLine::Terminate();
6062 return rv;
6065 GeckoProcessType XRE_GetProcessType() { return GetGeckoProcessType(); }
6067 const char* XRE_GetProcessTypeString() {
6068 return XRE_GeckoProcessTypeToString(XRE_GetProcessType());
6071 bool XRE_IsE10sParentProcess() {
6072 #ifdef MOZ_WIDGET_ANDROID
6073 return XRE_IsParentProcess() && BrowserTabsRemoteAutostart() &&
6074 mozilla::jni::IsAvailable();
6075 #else
6076 return XRE_IsParentProcess() && BrowserTabsRemoteAutostart();
6077 #endif
6080 #define GECKO_PROCESS_TYPE(enum_value, enum_name, string_name, proc_typename, \
6081 process_bin_type, procinfo_typename, \
6082 webidl_typename, allcaps_name) \
6083 bool XRE_Is##proc_typename##Process() { \
6084 return XRE_GetProcessType() == GeckoProcessType_##enum_name; \
6086 #include "mozilla/GeckoProcessTypes.h"
6087 #undef GECKO_PROCESS_TYPE
6089 bool XRE_UseNativeEventProcessing() {
6090 switch (XRE_GetProcessType()) {
6091 #if defined(XP_MACOSX) || defined(XP_WIN)
6092 case GeckoProcessType_RDD:
6093 case GeckoProcessType_Socket:
6094 return false;
6095 case GeckoProcessType_Utility: {
6096 # if defined(XP_WIN)
6097 auto upc = mozilla::ipc::UtilityProcessChild::Get();
6098 MOZ_ASSERT(upc);
6100 using SboxKind = mozilla::ipc::SandboxingKind;
6101 // These processes are used as external hosts for accessing Windows
6102 // APIs which (may) require a Windows native event loop.
6103 return upc->mSandbox == SboxKind::WINDOWS_UTILS ||
6104 upc->mSandbox == SboxKind::WINDOWS_FILE_DIALOG;
6105 # else
6106 return false;
6107 # endif // defined(XP_WIN)
6109 #endif // defined(XP_MACOSX) || defined(XP_WIN)
6110 case GeckoProcessType_GMPlugin:
6111 return mozilla::gmp::GMPProcessChild::UseNativeEventProcessing();
6112 case GeckoProcessType_Content:
6113 return StaticPrefs::dom_ipc_useNativeEventProcessing_content();
6114 default:
6115 return true;
6119 namespace mozilla {
6121 uint32_t GetMaxWebProcessCount() {
6122 // multiOptOut is in int to allow us to run multiple experiments without
6123 // introducing multiple prefs a la the autostart.N prefs.
6124 if (Preferences::GetInt("dom.ipc.multiOptOut", 0) >=
6125 nsIXULRuntime::E10S_MULTI_EXPERIMENT) {
6126 return 1;
6129 const char* optInPref = "dom.ipc.processCount";
6130 uint32_t optInPrefValue = Preferences::GetInt(optInPref, 1);
6131 return std::max(1u, optInPrefValue);
6134 const char* PlatformBuildID() { return gToolkitBuildID; }
6136 } // namespace mozilla
6138 void SetupErrorHandling(const char* progname) {
6139 #ifdef XP_WIN
6140 /* On Windows XPSP3 and Windows Vista if DEP is configured off-by-default
6141 we still want DEP protection: enable it explicitly and programmatically.
6143 This function is not available on WinXPSP2 so we dynamically load it.
6146 HMODULE kernel32 = GetModuleHandleW(L"kernel32.dll");
6147 SetProcessDEPPolicyFunc _SetProcessDEPPolicy =
6148 (SetProcessDEPPolicyFunc)GetProcAddress(kernel32, "SetProcessDEPPolicy");
6149 if (_SetProcessDEPPolicy) _SetProcessDEPPolicy(PROCESS_DEP_ENABLE);
6150 #endif
6152 #ifdef XP_WIN
6153 // Suppress the "DLL Foo could not be found" dialog, such that if dependent
6154 // libraries (such as GDI+) are not preset, we gracefully fail to load those
6155 // XPCOM components, instead of being ungraceful.
6156 UINT realMode = SetErrorMode(0);
6157 realMode |= SEM_FAILCRITICALERRORS;
6158 // If XRE_NO_WINDOWS_CRASH_DIALOG is set, suppress displaying the "This
6159 // application has crashed" dialog box. This is mainly useful for
6160 // automated testing environments, e.g. tinderbox, where there's no need
6161 // for a dozen of the dialog boxes to litter the console
6162 if (getenv("XRE_NO_WINDOWS_CRASH_DIALOG"))
6163 realMode |= SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX;
6165 SetErrorMode(realMode);
6167 #endif
6169 InstallSignalHandlers(progname);
6171 // Unbuffer stdout, needed for tinderbox tests.
6172 setbuf(stdout, 0);
6175 static bool gRunSelfAsContentProc = false;
6177 void XRE_EnableSameExecutableForContentProc() {
6178 if (!PR_GetEnv("MOZ_SEPARATE_CHILD_PROCESS")) {
6179 gRunSelfAsContentProc = true;
6183 mozilla::BinPathType XRE_GetChildProcBinPathType(
6184 GeckoProcessType aProcessType) {
6185 MOZ_ASSERT(aProcessType != GeckoProcessType_Default);
6187 if (!gRunSelfAsContentProc) {
6188 return BinPathType::PluginContainer;
6191 #ifdef XP_WIN
6192 // On Windows, plugin-container may or may not be used depending on
6193 // the process type (e.g., actual plugins vs. content processes)
6194 switch (aProcessType) {
6195 # define GECKO_PROCESS_TYPE(enum_value, enum_name, string_name, \
6196 proc_typename, process_bin_type, \
6197 procinfo_typename, webidl_typename, allcaps_name) \
6198 case GeckoProcessType_##enum_name: \
6199 return BinPathType::process_bin_type;
6200 # include "mozilla/GeckoProcessTypes.h"
6201 # undef GECKO_PROCESS_TYPE
6202 default:
6203 return BinPathType::PluginContainer;
6205 #else
6206 // On (non-macOS) Unix, plugin-container isn't used (except in cases
6207 // like xpcshell that are handled by the gRunSelfAsContentProc check
6208 // above). It isn't necessary the way it is on other platforms, and
6209 // it interferes with using the fork server.
6210 return BinPathType::Self;
6211 #endif
6214 // From mozglue/static/rust/lib.rs
6215 extern "C" void install_rust_hooks();
6217 struct InstallRustHooks {
6218 InstallRustHooks() { install_rust_hooks(); }
6221 InstallRustHooks sInstallRustHooks;
6223 #ifdef MOZ_ASAN_REPORTER
6224 void setASanReporterPath(nsIFile* aDir) {
6225 nsCOMPtr<nsIFile> dir;
6226 aDir->Clone(getter_AddRefs(dir));
6228 dir->Append(u"asan"_ns);
6229 nsresult rv = dir->Create(nsIFile::DIRECTORY_TYPE, 0700);
6230 if (NS_WARN_IF(NS_FAILED(rv) && rv != NS_ERROR_FILE_ALREADY_EXISTS)) {
6231 MOZ_CRASH("[ASan Reporter] Unable to create crash directory.");
6234 dir->Append(u"ff_asan_log"_ns);
6236 # ifdef XP_WIN
6237 nsAutoString nspathW;
6238 rv = dir->GetPath(nspathW);
6239 NS_ConvertUTF16toUTF8 nspath(nspathW);
6240 # else
6241 nsAutoCString nspath;
6242 rv = dir->GetNativePath(nspath);
6243 # endif
6244 if (NS_FAILED(rv)) {
6245 MOZ_CRASH("[ASan Reporter] Unable to get native path for crash directory.");
6248 __sanitizer_set_report_path(nspath.get());
6250 #endif