Bug 1885602 - Part 4: Implement navigating to the settings from the menu header for...
[gecko.git] / toolkit / xre / nsAppRunner.cpp
blob35c58d9b36049d00b7dbcf29cf6df9b899dd705f
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 kPrefSetDefaultBrowserUserChoicePref[] =
289 "browser.shell.setDefaultBrowserUserChoice";
290 #endif // defined(MOZ_DEFAULT_BROWSER_AGENT)
292 #if defined(XP_WIN)
293 static const char kPrefThemeId[] = "extensions.activeThemeID";
294 static const char kPrefBrowserStartupBlankWindow[] =
295 "browser.startup.blankWindow";
296 static const char kPrefPreXulSkeletonUI[] = "browser.startup.preXulSkeletonUI";
297 #endif // defined(XP_WIN)
299 #if defined(MOZ_WIDGET_GTK)
300 constexpr nsLiteralCString kStartupTokenNames[] = {
301 "XDG_ACTIVATION_TOKEN"_ns,
302 "DESKTOP_STARTUP_ID"_ns,
304 #endif
306 int gArgc;
307 char** gArgv;
309 static const char gToolkitVersion[] = MOZ_STRINGIFY(GRE_MILESTONE);
310 // The gToolkitBuildID global is defined to MOZ_BUILDID via gen_buildid.py
311 // in toolkit/library. See related comment in toolkit/library/moz.build.
312 extern const char gToolkitBuildID[];
314 static nsIProfileLock* gProfileLock;
315 #if defined(MOZ_HAS_REMOTE)
316 static nsRemoteService* gRemoteService;
317 bool gRestartWithoutRemote = false;
318 #endif
320 int gRestartArgc;
321 char** gRestartArgv;
323 // If gRestartedByOS is set, we were automatically restarted by the OS.
324 bool gRestartedByOS = false;
326 bool gIsGtest = false;
328 bool gKioskMode = false;
329 int gKioskMonitor = -1;
331 bool gAllowContentAnalysisArgPresent = false;
333 nsString gAbsoluteArgv0Path;
335 #if defined(XP_WIN)
336 nsString gProcessStartupShortcut;
337 #endif
339 #if defined(MOZ_WIDGET_GTK)
340 # include <glib.h>
341 # include "mozilla/WidgetUtilsGtk.h"
342 # include <gtk/gtk.h>
343 # ifdef MOZ_WAYLAND
344 # include <gdk/gdkwayland.h>
345 # include "mozilla/widget/nsWaylandDisplay.h"
346 # include "wayland-proxy.h"
347 # endif
348 # ifdef MOZ_X11
349 # include <gdk/gdkx.h>
350 # endif /* MOZ_X11 */
351 #endif
353 #if defined(MOZ_WAYLAND)
354 std::unique_ptr<WaylandProxy> gWaylandProxy;
355 #endif
357 #include "BinaryPath.h"
359 #ifdef MOZ_LOGGING
360 # include "mozilla/Logging.h"
361 extern mozilla::LazyLogModule gWidgetWaylandLog;
362 #endif /* MOZ_LOGGING */
364 #ifdef FUZZING
365 # include "FuzzerRunner.h"
367 namespace mozilla {
368 FuzzerRunner* fuzzerRunner = 0;
369 } // namespace mozilla
371 # ifdef LIBFUZZER
372 void XRE_LibFuzzerSetDriver(LibFuzzerDriver aDriver) {
373 mozilla::fuzzerRunner->setParams(aDriver);
375 # endif
376 #endif // FUZZING
378 // Undo X11/X.h's definition of None
379 #undef None
381 namespace mozilla {
382 int (*RunGTest)(int*, char**) = 0;
384 bool RunningGTest() { return RunGTest; }
385 } // namespace mozilla
387 using namespace mozilla;
388 using namespace mozilla::widget;
389 using namespace mozilla::startup;
390 using mozilla::Unused;
391 using mozilla::dom::ContentChild;
392 using mozilla::dom::ContentParent;
393 using mozilla::dom::quota::QuotaManager;
394 using mozilla::intl::LocaleService;
395 using mozilla::scache::StartupCache;
397 // Save the given word to the specified environment variable.
398 static void MOZ_NEVER_INLINE SaveWordToEnv(const char* name,
399 const nsACString& word) {
400 char* expr =
401 Smprintf("%s=%s", name, PromiseFlatCString(word).get()).release();
402 if (expr) PR_SetEnv(expr);
403 // We intentionally leak |expr| here since it is required by PR_SetEnv.
406 // Save the path of the given file to the specified environment variable.
407 static void SaveFileToEnv(const char* name, nsIFile* file) {
408 #ifdef XP_WIN
409 nsAutoString path;
410 file->GetPath(path);
411 SetEnvironmentVariableW(NS_ConvertASCIItoUTF16(name).get(), path.get());
412 #else
413 nsAutoCString path;
414 file->GetNativePath(path);
415 SaveWordToEnv(name, path);
416 #endif
419 static bool gIsExpectedExit = false;
421 void MozExpectedExit() { gIsExpectedExit = true; }
424 * Runs atexit() to catch unexpected exit from 3rd party libraries like the
425 * Intel graphics driver calling exit in an error condition. When they
426 * call exit() to report an error we won't shutdown correctly and wont catch
427 * the issue with our crash reporter.
429 static void UnexpectedExit() {
430 if (!gIsExpectedExit) {
431 gIsExpectedExit = true; // Don't risk re-entrency issues when crashing.
432 MOZ_CRASH("Exit called by third party code.");
436 #if defined(MOZ_WAYLAND)
437 bool IsWaylandEnabled() {
438 static bool isWaylandEnabled = []() {
439 const char* waylandDisplay = PR_GetEnv("WAYLAND_DISPLAY");
440 if (!waylandDisplay) {
441 return false;
443 if (!PR_GetEnv("DISPLAY")) {
444 // No X11 display, so try to run wayland.
445 return true;
447 // MOZ_ENABLE_WAYLAND is our primary Wayland on/off switch.
448 if (const char* waylandPref = PR_GetEnv("MOZ_ENABLE_WAYLAND")) {
449 return *waylandPref == '1';
451 if (const char* backendPref = PR_GetEnv("GDK_BACKEND")) {
452 if (!strncmp(backendPref, "wayland", 7)) {
453 NS_WARNING(
454 "Wayland backend should be enabled by MOZ_ENABLE_WAYLAND=1."
455 "GDK_BACKEND is a Gtk3 debug variable and may cause issues.");
456 return true;
459 // Enable by default when we're running on a recent enough GTK version. We'd
460 // like to check further details like compositor version and so on ideally
461 // to make sure we don't enable it on old Mutter or what not, but we can't,
462 // so let's assume that if the user is running on a Wayland session by
463 // default we're ok, since either the distro has enabled Wayland by default,
464 // or the user has gone out of their way to use Wayland.
465 return !gtk_check_version(3, 24, 30);
466 }();
467 return isWaylandEnabled;
469 #else
470 bool IsWaylandEnabled() { return false; }
471 #endif
474 * Output a string to the user. This method is really only meant to be used to
475 * output last-ditch error messages designed for developers NOT END USERS.
477 * @param isError
478 * Pass true to indicate severe errors.
479 * @param fmt
480 * printf-style format string followed by arguments.
482 static MOZ_FORMAT_PRINTF(2, 3) void Output(bool isError, const char* fmt, ...) {
483 va_list ap;
484 va_start(ap, fmt);
486 #if defined(XP_WIN) && !MOZ_WINCONSOLE
487 SmprintfPointer msg = mozilla::Vsmprintf(fmt, ap);
488 if (msg) {
489 UINT flags = MB_OK;
490 if (isError)
491 flags |= MB_ICONERROR;
492 else
493 flags |= MB_ICONINFORMATION;
495 wchar_t wide_msg[1024];
496 MultiByteToWideChar(CP_ACP, 0, msg.get(), -1, wide_msg,
497 sizeof(wide_msg) / sizeof(wchar_t));
499 MessageBoxW(nullptr, wide_msg, L"XULRunner", flags);
501 #elif defined(MOZ_WIDGET_ANDROID)
502 SmprintfPointer msg = mozilla::Vsmprintf(fmt, ap);
503 if (msg) {
504 __android_log_print(isError ? ANDROID_LOG_ERROR : ANDROID_LOG_INFO,
505 "GeckoRuntime", "%s", msg.get());
507 #else
508 vfprintf(stderr, fmt, ap);
509 #endif
511 va_end(ap);
515 * Check for a commandline flag. If the flag takes a parameter, the
516 * parameter is returned in aParam. Flags may be in the form -arg or
517 * --arg (or /arg on win32).
519 * @param aArg the parameter to check. Must be lowercase.
520 * @param aParam if non-null, the -arg <data> will be stored in this pointer.
521 * This is *not* allocated, but rather a pointer to the argv data.
522 * @param aFlags flags @see CheckArgFlag
524 static ArgResult CheckArg(const char* aArg, const char** aParam = nullptr,
525 CheckArgFlag aFlags = CheckArgFlag::RemoveArg) {
526 MOZ_ASSERT(gArgv, "gArgv must be initialized before CheckArg()");
527 return CheckArg(gArgc, gArgv, aArg, aParam, aFlags);
531 * Check for a commandline flag. Ignore data that's passed in with the flag.
532 * Flags may be in the form -arg or --arg (or /arg on win32).
533 * Will not remove flag if found.
535 * @param aArg the parameter to check. Must be lowercase.
537 static ArgResult CheckArgExists(const char* aArg) {
538 return CheckArg(aArg, nullptr, CheckArgFlag::None);
541 bool gSafeMode = false;
542 bool gFxREmbedded = false;
544 enum E10sStatus {
545 kE10sEnabledByDefault,
546 kE10sForceDisabled,
549 static bool gBrowserTabsRemoteAutostart = false;
550 static E10sStatus gBrowserTabsRemoteStatus;
551 static bool gBrowserTabsRemoteAutostartInitialized = false;
553 namespace mozilla {
555 bool BrowserTabsRemoteAutostart() {
556 if (gBrowserTabsRemoteAutostartInitialized) {
557 return gBrowserTabsRemoteAutostart;
559 gBrowserTabsRemoteAutostartInitialized = true;
561 // If we're not in the parent process, we are running E10s.
562 if (!XRE_IsParentProcess()) {
563 gBrowserTabsRemoteAutostart = true;
564 return gBrowserTabsRemoteAutostart;
567 gBrowserTabsRemoteAutostart = true;
568 E10sStatus status = kE10sEnabledByDefault;
570 // We use "are non-local connections disabled" as a proxy for
571 // "are we running some kind of automated test". It would be nicer to use
572 // xpc::IsInAutomation(), but that depends on some prefs being set, which
573 // they are not in (at least) gtests (where we can't) and xpcshell.
574 // Long-term, hopefully we can make all tests e10s-friendly,
575 // then we could remove this automation-only env variable.
576 if (gBrowserTabsRemoteAutostart && xpc::AreNonLocalConnectionsDisabled()) {
577 const char* forceDisable = PR_GetEnv("MOZ_FORCE_DISABLE_E10S");
578 if (forceDisable && !strcmp(forceDisable, "1")) {
579 gBrowserTabsRemoteAutostart = false;
580 status = kE10sForceDisabled;
584 gBrowserTabsRemoteStatus = status;
586 return gBrowserTabsRemoteAutostart;
589 } // namespace mozilla
591 // Win32k Infrastructure ==============================================
593 // This bool tells us if we have initialized the following two statics
594 // upon startup.
596 static bool gWin32kInitialized = false;
598 // Win32k Lockdown for the current session is determined once, at startup,
599 // and then remains the same for the duration of the session.
601 static nsIXULRuntime::ContentWin32kLockdownState gWin32kStatus;
603 // The status of the win32k experiment. It is determined once, at startup,
604 // and then remains the same for the duration of the session.
606 static nsIXULRuntime::ExperimentStatus gWin32kExperimentStatus =
607 nsIXULRuntime::eExperimentStatusUnenrolled;
609 #ifdef XP_WIN
610 // The states for win32k lockdown can be generalized to:
611 // - User doesn't meet requirements (bad OS, webrender, remotegl) aka
612 // PersistentRequirement
613 // - User has Safe Mode enabled, Win32k Disabled by Env Var, or E10S disabled
614 // by Env Var aka TemporaryRequirement
615 // - User has set the win32k pref to something non-default aka NonDefaultPref
616 // - User has been enrolled in the experiment and does what it says aka
617 // Enrolled
618 // - User does the default aka Default
620 // We expect the below behvaior. In the code, there may be references to these
621 // behaviors (e.g. [A]) but not always.
623 // [A] Becoming enrolled in the experiment while NonDefaultPref disqualifies
624 // you upon next browser start
625 // [B] Becoming enrolled in the experiment while PersistentRequirement
626 // disqualifies you upon next browser start
627 // [C] Becoming enrolled in the experiment while TemporaryRequirement does not
628 // disqualify you
629 // [D] Becoming enrolled in the experiment will only take effect after restart
630 // [E] While enrolled, becoming PersistentRequirement will not disqualify you
631 // until browser restart, but if the state is present at browser start,
632 // will disqualify you. Additionally, it will not affect the session value
633 // of gWin32kStatus.
634 // XXX(bobowen): I hope both webrender and wbgl.out-of-process require a
635 // restart to take effect!
636 // [F] While enrolled, becoming NonDefaultPref will disqualify you upon next
637 // browser start
638 // [G] While enrolled, becoming TemporaryRequirement will _not_ disqualify you,
639 // but the session status will prevent win32k lockdown from taking effect.
641 // The win32k pref
642 static const char kPrefWin32k[] = "security.sandbox.content.win32k-disable";
644 // The current enrollment status as controlled by Normandy. This value is only
645 // stored in the default preference branch, and is not persisted across
646 // sessions by the preference service. It therefore isn't available early
647 // enough at startup, and needs to be synced to a preference in the user
648 // branch which is persisted across sessions.
649 static const char kPrefWin32kExperimentEnrollmentStatus[] =
650 "security.sandbox.content.win32k-experiment.enrollmentStatus";
652 // The enrollment status to be used at browser startup. This automatically
653 // synced from the above enrollmentStatus preference whenever the latter is
654 // changed. We reused the Fission experiment enum - it can have any of the
655 // values defined in the `nsIXULRuntime_ExperimentStatus` enum _except_ rollout.
656 // Meanings are documented in the declaration of
657 // `nsIXULRuntime.fissionExperimentStatus`
658 static const char kPrefWin32kExperimentStartupEnrollmentStatus[] =
659 "security.sandbox.content.win32k-experiment.startupEnrollmentStatus";
661 namespace mozilla {
663 bool Win32kExperimentEnrolled() {
664 MOZ_ASSERT(XRE_IsParentProcess());
665 return gWin32kExperimentStatus == nsIXULRuntime::eExperimentStatusControl ||
666 gWin32kExperimentStatus == nsIXULRuntime::eExperimentStatusTreatment;
669 } // namespace mozilla
671 static bool Win32kRequirementsUnsatisfied(
672 nsIXULRuntime::ContentWin32kLockdownState aStatus) {
673 return aStatus == nsIXULRuntime::ContentWin32kLockdownState::
674 OperatingSystemNotSupported ||
675 aStatus ==
676 nsIXULRuntime::ContentWin32kLockdownState::MissingWebRender ||
677 aStatus ==
678 nsIXULRuntime::ContentWin32kLockdownState::MissingRemoteWebGL ||
679 aStatus ==
680 nsIXULRuntime::ContentWin32kLockdownState::DecodersArentRemote;
683 static void Win32kExperimentDisqualify() {
684 MOZ_ASSERT(XRE_IsParentProcess());
685 Preferences::SetUint(kPrefWin32kExperimentEnrollmentStatus,
686 nsIXULRuntime::eExperimentStatusDisqualified);
689 static void OnWin32kEnrollmentStatusChanged(const char* aPref, void* aData) {
690 auto newStatusInt =
691 Preferences::GetUint(kPrefWin32kExperimentEnrollmentStatus,
692 nsIXULRuntime::eExperimentStatusUnenrolled);
693 auto newStatus = newStatusInt < nsIXULRuntime::eExperimentStatusCount
694 ? nsIXULRuntime::ExperimentStatus(newStatusInt)
695 : nsIXULRuntime::eExperimentStatusDisqualified;
697 // Set the startup pref for next browser start [D]
698 Preferences::SetUint(kPrefWin32kExperimentStartupEnrollmentStatus, newStatus);
701 namespace {
702 // This observer is notified during `profile-before-change`, and ensures that
703 // the experiment enrollment status is synced over before the browser shuts
704 // down, even if it was not modified since win32k was initialized.
705 class Win32kEnrollmentStatusShutdownObserver final : public nsIObserver {
706 public:
707 NS_DECL_ISUPPORTS
709 NS_IMETHOD Observe(nsISupports* aSubject, const char* aTopic,
710 const char16_t* aData) override {
711 MOZ_ASSERT(!strcmp("profile-before-change", aTopic));
712 OnWin32kEnrollmentStatusChanged(kPrefWin32kExperimentEnrollmentStatus,
713 nullptr);
714 return NS_OK;
717 private:
718 ~Win32kEnrollmentStatusShutdownObserver() = default;
720 NS_IMPL_ISUPPORTS(Win32kEnrollmentStatusShutdownObserver, nsIObserver)
721 } // namespace
723 static void OnWin32kChanged(const char* aPref, void* aData) {
724 // If we're actively enrolled in the Win32k experiment, disqualify the user
725 // from the experiment if the Win32k pref is modified. [F]
726 if (Win32kExperimentEnrolled() && Preferences::HasUserValue(kPrefWin32k)) {
727 Win32kExperimentDisqualify();
731 #endif // XP_WIN
733 namespace mozilla {
734 void EnsureWin32kInitialized();
737 nsIXULRuntime::ContentWin32kLockdownState GetLiveWin32kLockdownState() {
738 #ifdef XP_WIN
740 // HasUserValue The Pref functions can only be called on main thread
741 MOZ_ASSERT(NS_IsMainThread());
743 # ifdef MOZ_BACKGROUNDTASKS
744 if (BackgroundTasks::IsBackgroundTaskMode()) {
745 // Let's bail out before loading all the graphics libs.
746 return nsIXULRuntime::ContentWin32kLockdownState::DisabledByDefault;
748 # endif
750 mozilla::EnsureWin32kInitialized();
751 gfxPlatform::GetPlatform();
753 if (gSafeMode) {
754 return nsIXULRuntime::ContentWin32kLockdownState::DisabledBySafeMode;
757 if (EnvHasValue("MOZ_ENABLE_WIN32K")) {
758 return nsIXULRuntime::ContentWin32kLockdownState::DisabledByEnvVar;
761 if (!mozilla::BrowserTabsRemoteAutostart()) {
762 return nsIXULRuntime::ContentWin32kLockdownState::DisabledByE10S;
765 // Win32k lockdown is available on Win8+, but we are initially limiting it to
766 // Windows 10 v1709 (build 16299) or later. Before this COM initialization
767 // currently fails if user32.dll has loaded before it is called.
768 if (!IsWin10FallCreatorsUpdateOrLater()) {
769 return nsIXULRuntime::ContentWin32kLockdownState::
770 OperatingSystemNotSupported;
774 ConflictingMitigationStatus conflictingMitigationStatus = {};
775 if (!detect_win32k_conflicting_mitigations(&conflictingMitigationStatus)) {
776 return nsIXULRuntime::ContentWin32kLockdownState::
777 IncompatibleMitigationPolicy;
779 if (conflictingMitigationStatus.caller_check ||
780 conflictingMitigationStatus.sim_exec ||
781 conflictingMitigationStatus.stack_pivot) {
782 return nsIXULRuntime::ContentWin32kLockdownState::
783 IncompatibleMitigationPolicy;
787 // Non-native theming is required as well
788 if (!StaticPrefs::widget_non_native_theme_enabled()) {
789 return nsIXULRuntime::ContentWin32kLockdownState::MissingNonNativeTheming;
792 // Win32k Lockdown requires Remote WebGL, but it may be disabled on
793 // certain hardware or virtual machines.
794 if (!gfx::gfxVars::AllowWebglOop() || !StaticPrefs::webgl_out_of_process()) {
795 return nsIXULRuntime::ContentWin32kLockdownState::MissingRemoteWebGL;
798 // Some (not sure exactly which) decoders are not compatible
799 if (!PDMFactory::AllDecodersAreRemote()) {
800 return nsIXULRuntime::ContentWin32kLockdownState::DecodersArentRemote;
803 bool prefSetByUser =
804 Preferences::HasUserValue("security.sandbox.content.win32k-disable");
805 bool prefValue = Preferences::GetBool(
806 "security.sandbox.content.win32k-disable", false, PrefValueKind::User);
807 bool defaultValue = Preferences::GetBool(
808 "security.sandbox.content.win32k-disable", false, PrefValueKind::Default);
810 if (prefSetByUser) {
811 if (prefValue) {
812 return nsIXULRuntime::ContentWin32kLockdownState::EnabledByUserPref;
813 } else {
814 return nsIXULRuntime::ContentWin32kLockdownState::DisabledByUserPref;
818 if (gWin32kExperimentStatus ==
819 nsIXULRuntime::ExperimentStatus::eExperimentStatusControl) {
820 return nsIXULRuntime::ContentWin32kLockdownState::DisabledByControlGroup;
821 } else if (gWin32kExperimentStatus ==
822 nsIXULRuntime::ExperimentStatus::eExperimentStatusTreatment) {
823 return nsIXULRuntime::ContentWin32kLockdownState::EnabledByTreatmentGroup;
826 if (defaultValue) {
827 return nsIXULRuntime::ContentWin32kLockdownState::EnabledByDefault;
828 } else {
829 return nsIXULRuntime::ContentWin32kLockdownState::DisabledByDefault;
832 #else
834 return nsIXULRuntime::ContentWin32kLockdownState::OperatingSystemNotSupported;
836 #endif
839 namespace mozilla {
841 void EnsureWin32kInitialized() {
842 if (gWin32kInitialized) {
843 return;
845 gWin32kInitialized = true;
847 #ifdef XP_WIN
849 // Initialize the Win32k experiment, configuring win32k's
850 // default, before checking other overrides. This allows opting-out of a
851 // Win32k experiment through about:preferences or about:config from a
852 // safemode session.
853 uint32_t experimentRaw =
854 Preferences::GetUint(kPrefWin32kExperimentStartupEnrollmentStatus,
855 nsIXULRuntime::eExperimentStatusUnenrolled);
856 gWin32kExperimentStatus =
857 experimentRaw < nsIXULRuntime::eExperimentStatusCount
858 ? nsIXULRuntime::ExperimentStatus(experimentRaw)
859 : nsIXULRuntime::eExperimentStatusDisqualified;
861 // Watch the experiment enrollment status pref to detect experiment
862 // disqualification, and ensure it is propagated for the next restart.
863 Preferences::RegisterCallback(&OnWin32kEnrollmentStatusChanged,
864 kPrefWin32kExperimentEnrollmentStatus);
865 if (nsCOMPtr<nsIObserverService> observerService =
866 mozilla::services::GetObserverService()) {
867 nsCOMPtr<nsIObserver> shutdownObserver =
868 new Win32kEnrollmentStatusShutdownObserver();
869 observerService->AddObserver(shutdownObserver, "profile-before-change",
870 false);
873 // If the user no longer qualifies because they edited a required pref, check
874 // that. [B] [E]
875 auto tmpStatus = GetLiveWin32kLockdownState();
876 if (Win32kExperimentEnrolled() && Win32kRequirementsUnsatisfied(tmpStatus)) {
877 Win32kExperimentDisqualify();
878 gWin32kExperimentStatus = nsIXULRuntime::eExperimentStatusDisqualified;
881 // If the user has overridden an active experiment by setting a user value for
882 // "security.sandbox.content.win32k-disable", disqualify the user from the
883 // experiment. [A] [F]
884 if (Preferences::HasUserValue(kPrefWin32k) && Win32kExperimentEnrolled()) {
885 Win32kExperimentDisqualify();
886 gWin32kExperimentStatus = nsIXULRuntime::eExperimentStatusDisqualified;
889 // Unlike Fission, we do not configure the default branch based on experiment
890 // enrollment status. Instead we check the startupEnrollmentPref in
891 // GetContentWin32kLockdownState()
893 Preferences::RegisterCallback(&OnWin32kChanged, kPrefWin32k);
895 // Set the state
896 gWin32kStatus = GetLiveWin32kLockdownState();
898 #else
899 gWin32kStatus =
900 nsIXULRuntime::ContentWin32kLockdownState::OperatingSystemNotSupported;
901 gWin32kExperimentStatus = nsIXULRuntime::eExperimentStatusUnenrolled;
903 #endif // XP_WIN
906 nsIXULRuntime::ContentWin32kLockdownState GetWin32kLockdownState() {
907 #ifdef XP_WIN
909 mozilla::EnsureWin32kInitialized();
910 return gWin32kStatus;
912 #else
914 return nsIXULRuntime::ContentWin32kLockdownState::OperatingSystemNotSupported;
916 #endif
919 } // namespace mozilla
921 // End Win32k Infrastructure ==========================================
923 // Fission Infrastructure =============================================
925 // Fission enablement for the current session is determined once, at startup,
926 // and then remains the same for the duration of the session.
928 // The following factors determine whether or not Fission is enabled for a
929 // session, in order of precedence:
931 // - Safe mode: In safe mode, Fission is never enabled.
933 // - The MOZ_FORCE_ENABLE_FISSION environment variable: If set to any value,
934 // Fission will be enabled.
936 // - The 'fission.autostart' preference, if it has been configured by the user.
937 static const char kPrefFissionAutostart[] = "fission.autostart";
939 // The computed FissionAutostart value for the session, read by content
940 // processes to initialize gFissionAutostart.
942 // This pref is locked, and only configured on the default branch, so should
943 // never be persisted in a profile.
944 static const char kPrefFissionAutostartSession[] = "fission.autostart.session";
947 // The computed FissionAutostart value for the session, read by content
948 // processes to initialize gFissionAutostart.
950 static bool gFissionAutostart = false;
951 static bool gFissionAutostartInitialized = false;
952 static nsIXULRuntime::FissionDecisionStatus gFissionDecisionStatus;
953 static void EnsureFissionAutostartInitialized() {
954 if (gFissionAutostartInitialized) {
955 return;
957 gFissionAutostartInitialized = true;
959 if (!XRE_IsParentProcess()) {
960 // This pref is configured for the current session by the parent process.
961 gFissionAutostart = Preferences::GetBool(kPrefFissionAutostartSession,
962 false, PrefValueKind::Default);
963 return;
966 if (!BrowserTabsRemoteAutostart()) {
967 gFissionAutostart = false;
968 if (gBrowserTabsRemoteStatus == kE10sForceDisabled) {
969 gFissionDecisionStatus = nsIXULRuntime::eFissionDisabledByE10sEnv;
970 } else {
971 gFissionDecisionStatus = nsIXULRuntime::eFissionDisabledByE10sOther;
973 } else if (EnvHasValue("MOZ_FORCE_ENABLE_FISSION")) {
974 gFissionAutostart = true;
975 gFissionDecisionStatus = nsIXULRuntime::eFissionEnabledByEnv;
976 } else if (EnvHasValue("MOZ_FORCE_DISABLE_FISSION")) {
977 gFissionAutostart = false;
978 gFissionDecisionStatus = nsIXULRuntime::eFissionDisabledByEnv;
979 } else {
980 // NOTE: This will take into account changes to the default due to
981 // `InitializeFissionExperimentStatus`.
982 gFissionAutostart = Preferences::GetBool(kPrefFissionAutostart, false);
983 if (Preferences::HasUserValue(kPrefFissionAutostart)) {
984 gFissionDecisionStatus = gFissionAutostart
985 ? nsIXULRuntime::eFissionEnabledByUserPref
986 : nsIXULRuntime::eFissionDisabledByUserPref;
987 } else {
988 gFissionDecisionStatus = gFissionAutostart
989 ? nsIXULRuntime::eFissionEnabledByDefault
990 : nsIXULRuntime::eFissionDisabledByDefault;
994 // Content processes cannot run the same logic as we're running in the parent
995 // process, as the current value of various preferences may have changed
996 // between launches. Instead, the content process will read the default branch
997 // of the locked `fission.autostart.session` preference to determine the value
998 // determined by this method.
999 Preferences::Unlock(kPrefFissionAutostartSession);
1000 Preferences::ClearUser(kPrefFissionAutostartSession);
1001 Preferences::SetBool(kPrefFissionAutostartSession, gFissionAutostart,
1002 PrefValueKind::Default);
1003 Preferences::Lock(kPrefFissionAutostartSession);
1006 namespace mozilla {
1008 bool FissionAutostart() {
1009 EnsureFissionAutostartInitialized();
1010 return gFissionAutostart;
1013 } // namespace mozilla
1015 // End Fission Infrastructure =========================================
1017 namespace mozilla {
1019 bool SessionHistoryInParent() {
1020 return FissionAutostart() ||
1021 !StaticPrefs::
1022 fission_disableSessionHistoryInParent_AtStartup_DoNotUseDirectly();
1025 bool SessionStorePlatformCollection() {
1026 return SessionHistoryInParent() &&
1027 !StaticPrefs::
1028 browser_sessionstore_disable_platform_collection_AtStartup_DoNotUseDirectly();
1031 bool BFCacheInParent() {
1032 return SessionHistoryInParent() &&
1033 StaticPrefs::fission_bfcacheInParent_DoNotUseDirectly();
1036 } // namespace mozilla
1039 * The nsXULAppInfo object implements nsIFactory so that it can be its own
1040 * singleton.
1042 class nsXULAppInfo : public nsIXULAppInfo,
1043 #ifdef XP_WIN
1044 public nsIWinAppHelper,
1045 #endif
1046 public nsICrashReporter,
1047 public nsIFinishDumpingCallback,
1048 public nsIXULRuntime
1051 public:
1052 constexpr nsXULAppInfo() = default;
1053 NS_DECL_ISUPPORTS_INHERITED
1054 NS_DECL_NSIPLATFORMINFO
1055 NS_DECL_NSIXULAPPINFO
1056 NS_DECL_NSIXULRUNTIME
1057 NS_DECL_NSICRASHREPORTER
1058 NS_DECL_NSIFINISHDUMPINGCALLBACK
1059 #ifdef XP_WIN
1060 NS_DECL_NSIWINAPPHELPER
1061 #endif
1064 NS_INTERFACE_MAP_BEGIN(nsXULAppInfo)
1065 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXULRuntime)
1066 NS_INTERFACE_MAP_ENTRY(nsIXULRuntime)
1067 #ifdef XP_WIN
1068 NS_INTERFACE_MAP_ENTRY(nsIWinAppHelper)
1069 #endif
1070 NS_INTERFACE_MAP_ENTRY(nsICrashReporter)
1071 NS_INTERFACE_MAP_ENTRY(nsIFinishDumpingCallback)
1072 NS_INTERFACE_MAP_ENTRY(nsIPlatformInfo)
1073 NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIXULAppInfo,
1074 gAppData || XRE_IsContentProcess())
1075 NS_INTERFACE_MAP_END
1077 NS_IMETHODIMP_(MozExternalRefCountType)
1078 nsXULAppInfo::AddRef() { return 1; }
1080 NS_IMETHODIMP_(MozExternalRefCountType)
1081 nsXULAppInfo::Release() { return 1; }
1083 NS_IMETHODIMP
1084 nsXULAppInfo::GetVendor(nsACString& aResult) {
1085 if (XRE_IsContentProcess()) {
1086 ContentChild* cc = ContentChild::GetSingleton();
1087 aResult = cc->GetAppInfo().vendor;
1088 return NS_OK;
1090 aResult.Assign(gAppData->vendor);
1092 return NS_OK;
1095 NS_IMETHODIMP
1096 nsXULAppInfo::GetName(nsACString& aResult) {
1097 if (XRE_IsContentProcess()) {
1098 ContentChild* cc = ContentChild::GetSingleton();
1099 aResult = cc->GetAppInfo().name;
1100 return NS_OK;
1103 #ifdef MOZ_WIDGET_ANDROID
1104 nsCString name = java::GeckoAppShell::GetAppName()->ToCString();
1105 aResult.Assign(std::move(name));
1106 #else
1107 aResult.Assign(gAppData->name);
1108 #endif
1110 return NS_OK;
1113 NS_IMETHODIMP
1114 nsXULAppInfo::GetID(nsACString& aResult) {
1115 if (XRE_IsContentProcess()) {
1116 ContentChild* cc = ContentChild::GetSingleton();
1117 aResult = cc->GetAppInfo().ID;
1118 return NS_OK;
1120 aResult.Assign(gAppData->ID);
1122 return NS_OK;
1125 NS_IMETHODIMP
1126 nsXULAppInfo::GetVersion(nsACString& aResult) {
1127 if (XRE_IsContentProcess()) {
1128 ContentChild* cc = ContentChild::GetSingleton();
1129 aResult = cc->GetAppInfo().version;
1130 return NS_OK;
1132 aResult.Assign(gAppData->version);
1134 return NS_OK;
1137 NS_IMETHODIMP
1138 nsXULAppInfo::GetPlatformVersion(nsACString& aResult) {
1139 aResult.Assign(gToolkitVersion);
1141 return NS_OK;
1144 NS_IMETHODIMP
1145 nsXULAppInfo::GetAppBuildID(nsACString& aResult) {
1146 if (XRE_IsContentProcess()) {
1147 ContentChild* cc = ContentChild::GetSingleton();
1148 aResult = cc->GetAppInfo().buildID;
1149 return NS_OK;
1151 aResult.Assign(gAppData->buildID);
1153 return NS_OK;
1156 NS_IMETHODIMP
1157 nsXULAppInfo::GetPlatformBuildID(nsACString& aResult) {
1158 aResult.Assign(gToolkitBuildID);
1160 return NS_OK;
1163 NS_IMETHODIMP
1164 nsXULAppInfo::GetUAName(nsACString& aResult) {
1165 if (XRE_IsContentProcess()) {
1166 ContentChild* cc = ContentChild::GetSingleton();
1167 aResult = cc->GetAppInfo().UAName;
1168 return NS_OK;
1170 aResult.Assign(gAppData->UAName);
1172 return NS_OK;
1175 NS_IMETHODIMP
1176 nsXULAppInfo::GetSourceURL(nsACString& aResult) {
1177 if (XRE_IsContentProcess()) {
1178 ContentChild* cc = ContentChild::GetSingleton();
1179 aResult = cc->GetAppInfo().sourceURL;
1180 return NS_OK;
1182 aResult.Assign(gAppData->sourceURL);
1184 return NS_OK;
1187 NS_IMETHODIMP
1188 nsXULAppInfo::GetUpdateURL(nsACString& aResult) {
1189 if (XRE_IsContentProcess()) {
1190 ContentChild* cc = ContentChild::GetSingleton();
1191 aResult = cc->GetAppInfo().updateURL;
1192 return NS_OK;
1194 aResult.Assign(gAppData->updateURL);
1196 return NS_OK;
1199 NS_IMETHODIMP
1200 nsXULAppInfo::GetLogConsoleErrors(bool* aResult) {
1201 *aResult = gLogConsoleErrors;
1202 return NS_OK;
1205 NS_IMETHODIMP
1206 nsXULAppInfo::SetLogConsoleErrors(bool aValue) {
1207 gLogConsoleErrors = aValue;
1208 return NS_OK;
1211 NS_IMETHODIMP
1212 nsXULAppInfo::GetInSafeMode(bool* aResult) {
1213 *aResult = gSafeMode;
1214 return NS_OK;
1217 NS_IMETHODIMP
1218 nsXULAppInfo::GetOS(nsACString& aResult) {
1219 aResult.AssignLiteral(OS_TARGET);
1220 return NS_OK;
1223 NS_IMETHODIMP
1224 nsXULAppInfo::GetXPCOMABI(nsACString& aResult) {
1225 #ifdef TARGET_XPCOM_ABI
1226 aResult.AssignLiteral(TARGET_XPCOM_ABI);
1227 return NS_OK;
1228 #else
1229 return NS_ERROR_NOT_AVAILABLE;
1230 #endif
1233 NS_IMETHODIMP
1234 nsXULAppInfo::GetWidgetToolkit(nsACString& aResult) {
1235 aResult.AssignLiteral(MOZ_WIDGET_TOOLKIT);
1236 return NS_OK;
1239 // Ensure that the GeckoProcessType enum, defined in xpcom/build/nsXULAppAPI.h,
1240 // is synchronized with the const unsigned longs defined in
1241 // xpcom/system/nsIXULRuntime.idl.
1242 #define GECKO_PROCESS_TYPE(enum_value, enum_name, string_name, proc_typename, \
1243 process_bin_type, procinfo_typename, \
1244 webidl_typename, allcaps_name) \
1245 static_assert(nsIXULRuntime::PROCESS_TYPE_##allcaps_name == \
1246 static_cast<int>(GeckoProcessType_##enum_name), \
1247 "GeckoProcessType in nsXULAppAPI.h not synchronized with " \
1248 "nsIXULRuntime.idl");
1249 #include "mozilla/GeckoProcessTypes.h"
1250 #undef GECKO_PROCESS_TYPE
1252 // .. and ensure that that is all of them:
1253 static_assert(GeckoProcessType_Utility + 1 == GeckoProcessType_End,
1254 "Did not find the final GeckoProcessType");
1256 NS_IMETHODIMP
1257 nsXULAppInfo::GetProcessType(uint32_t* aResult) {
1258 NS_ENSURE_ARG_POINTER(aResult);
1259 *aResult = XRE_GetProcessType();
1260 return NS_OK;
1263 NS_IMETHODIMP
1264 nsXULAppInfo::GetProcessID(uint32_t* aResult) {
1265 #ifdef XP_WIN
1266 *aResult = GetCurrentProcessId();
1267 #else
1268 *aResult = getpid();
1269 #endif
1270 return NS_OK;
1273 NS_IMETHODIMP
1274 nsXULAppInfo::GetUniqueProcessID(uint64_t* aResult) {
1275 if (XRE_IsContentProcess()) {
1276 ContentChild* cc = ContentChild::GetSingleton();
1277 *aResult = cc->GetID();
1278 } else {
1279 *aResult = 0;
1281 return NS_OK;
1284 NS_IMETHODIMP
1285 nsXULAppInfo::GetRemoteType(nsACString& aRemoteType) {
1286 if (XRE_IsContentProcess()) {
1287 aRemoteType = ContentChild::GetSingleton()->GetRemoteType();
1288 } else {
1289 aRemoteType = NOT_REMOTE_TYPE;
1292 return NS_OK;
1295 static nsCString gLastAppVersion;
1296 static nsCString gLastAppBuildID;
1298 NS_IMETHODIMP
1299 nsXULAppInfo::GetLastAppVersion(nsACString& aResult) {
1300 if (XRE_IsContentProcess()) {
1301 return NS_ERROR_NOT_AVAILABLE;
1304 if (!gLastAppVersion.IsVoid() && gLastAppVersion.IsEmpty()) {
1305 NS_WARNING("Attempt to retrieve lastAppVersion before it has been set.");
1306 return NS_ERROR_NOT_AVAILABLE;
1309 aResult.Assign(gLastAppVersion);
1310 return NS_OK;
1313 NS_IMETHODIMP
1314 nsXULAppInfo::GetLastAppBuildID(nsACString& aResult) {
1315 if (XRE_IsContentProcess()) {
1316 return NS_ERROR_NOT_AVAILABLE;
1319 if (!gLastAppBuildID.IsVoid() && gLastAppBuildID.IsEmpty()) {
1320 NS_WARNING("Attempt to retrieve lastAppBuildID before it has been set.");
1321 return NS_ERROR_NOT_AVAILABLE;
1324 aResult.Assign(gLastAppBuildID);
1325 return NS_OK;
1328 NS_IMETHODIMP
1329 nsXULAppInfo::GetFissionAutostart(bool* aResult) {
1330 *aResult = FissionAutostart();
1331 return NS_OK;
1334 NS_IMETHODIMP
1335 nsXULAppInfo::GetWin32kExperimentStatus(ExperimentStatus* aResult) {
1336 if (!XRE_IsParentProcess()) {
1337 return NS_ERROR_NOT_AVAILABLE;
1340 EnsureWin32kInitialized();
1341 *aResult = gWin32kExperimentStatus;
1342 return NS_OK;
1345 NS_IMETHODIMP
1346 nsXULAppInfo::GetWin32kLiveStatusTestingOnly(
1347 nsIXULRuntime::ContentWin32kLockdownState* aResult) {
1348 if (!XRE_IsParentProcess()) {
1349 return NS_ERROR_NOT_AVAILABLE;
1352 EnsureWin32kInitialized();
1353 *aResult = GetLiveWin32kLockdownState();
1354 return NS_OK;
1357 NS_IMETHODIMP
1358 nsXULAppInfo::GetWin32kSessionStatus(
1359 nsIXULRuntime::ContentWin32kLockdownState* aResult) {
1360 if (!XRE_IsParentProcess()) {
1361 return NS_ERROR_NOT_AVAILABLE;
1364 EnsureWin32kInitialized();
1365 *aResult = gWin32kStatus;
1366 return NS_OK;
1369 NS_IMETHODIMP
1370 nsXULAppInfo::GetFissionDecisionStatus(FissionDecisionStatus* aResult) {
1371 if (!XRE_IsParentProcess()) {
1372 return NS_ERROR_NOT_AVAILABLE;
1375 EnsureFissionAutostartInitialized();
1377 MOZ_ASSERT(gFissionDecisionStatus != eFissionStatusUnknown);
1378 *aResult = gFissionDecisionStatus;
1379 return NS_OK;
1382 NS_IMETHODIMP
1383 nsXULAppInfo::GetFissionDecisionStatusString(nsACString& aResult) {
1384 if (!XRE_IsParentProcess()) {
1385 return NS_ERROR_NOT_AVAILABLE;
1388 EnsureFissionAutostartInitialized();
1389 switch (gFissionDecisionStatus) {
1390 case eFissionExperimentControl:
1391 aResult = "experimentControl";
1392 break;
1393 case eFissionExperimentTreatment:
1394 aResult = "experimentTreatment";
1395 break;
1396 case eFissionDisabledByE10sEnv:
1397 aResult = "disabledByE10sEnv";
1398 break;
1399 case eFissionEnabledByEnv:
1400 aResult = "enabledByEnv";
1401 break;
1402 case eFissionDisabledByEnv:
1403 aResult = "disabledByEnv";
1404 break;
1405 case eFissionEnabledByDefault:
1406 aResult = "enabledByDefault";
1407 break;
1408 case eFissionDisabledByDefault:
1409 aResult = "disabledByDefault";
1410 break;
1411 case eFissionEnabledByUserPref:
1412 aResult = "enabledByUserPref";
1413 break;
1414 case eFissionDisabledByUserPref:
1415 aResult = "disabledByUserPref";
1416 break;
1417 case eFissionDisabledByE10sOther:
1418 aResult = "disabledByE10sOther";
1419 break;
1420 case eFissionEnabledByRollout:
1421 aResult = "enabledByRollout";
1422 break;
1423 default:
1424 MOZ_ASSERT_UNREACHABLE("Unexpected enum value");
1426 return NS_OK;
1429 NS_IMETHODIMP
1430 nsXULAppInfo::GetSessionHistoryInParent(bool* aResult) {
1431 *aResult = SessionHistoryInParent();
1432 return NS_OK;
1435 NS_IMETHODIMP
1436 nsXULAppInfo::GetSessionStorePlatformCollection(bool* aResult) {
1437 *aResult = SessionStorePlatformCollection();
1438 return NS_OK;
1441 NS_IMETHODIMP
1442 nsXULAppInfo::GetBrowserTabsRemoteAutostart(bool* aResult) {
1443 *aResult = BrowserTabsRemoteAutostart();
1444 return NS_OK;
1447 NS_IMETHODIMP
1448 nsXULAppInfo::GetMaxWebProcessCount(uint32_t* aResult) {
1449 *aResult = mozilla::GetMaxWebProcessCount();
1450 return NS_OK;
1453 NS_IMETHODIMP
1454 nsXULAppInfo::GetAccessibilityEnabled(bool* aResult) {
1455 #ifdef ACCESSIBILITY
1456 *aResult = GetAccService() != nullptr;
1457 #else
1458 *aResult = false;
1459 #endif
1460 return NS_OK;
1463 NS_IMETHODIMP
1464 nsXULAppInfo::GetAccessibilityInstantiator(nsAString& aInstantiator) {
1465 #if defined(ACCESSIBILITY) && defined(XP_WIN)
1466 if (!GetAccService()) {
1467 aInstantiator.Truncate();
1468 return NS_OK;
1470 nsAutoString ipClientInfo;
1471 a11y::Compatibility::GetHumanReadableConsumersStr(ipClientInfo);
1472 aInstantiator.Append(ipClientInfo);
1473 aInstantiator.AppendLiteral("|");
1475 nsCOMPtr<nsIFile> oopClientExe;
1476 if (a11y::GetInstantiator(getter_AddRefs(oopClientExe))) {
1477 nsAutoString oopClientInfo;
1478 if (NS_SUCCEEDED(oopClientExe->GetPath(oopClientInfo))) {
1479 aInstantiator.Append(oopClientInfo);
1482 #else
1483 aInstantiator.Truncate();
1484 #endif
1485 return NS_OK;
1488 NS_IMETHODIMP
1489 nsXULAppInfo::GetIs64Bit(bool* aResult) {
1490 #ifdef HAVE_64BIT_BUILD
1491 *aResult = true;
1492 #else
1493 *aResult = false;
1494 #endif
1495 return NS_OK;
1498 NS_IMETHODIMP
1499 nsXULAppInfo::GetIsTextRecognitionSupported(bool* aResult) {
1500 *aResult = widget::TextRecognition::IsSupported();
1501 return NS_OK;
1504 NS_IMETHODIMP
1505 nsXULAppInfo::EnsureContentProcess() {
1506 if (!XRE_IsParentProcess()) return NS_ERROR_NOT_AVAILABLE;
1508 RefPtr<ContentParent> unused =
1509 ContentParent::GetNewOrUsedBrowserProcess(DEFAULT_REMOTE_TYPE);
1510 return NS_OK;
1513 NS_IMETHODIMP
1514 nsXULAppInfo::InvalidateCachesOnRestart() {
1515 nsCOMPtr<nsIFile> file;
1516 nsresult rv =
1517 NS_GetSpecialDirectory(NS_APP_PROFILE_DIR_STARTUP, getter_AddRefs(file));
1518 if (NS_FAILED(rv)) return rv;
1519 if (!file) return NS_ERROR_NOT_AVAILABLE;
1521 file->AppendNative(FILE_COMPATIBILITY_INFO);
1523 nsINIParser parser;
1524 rv = parser.Init(file);
1525 if (NS_FAILED(rv)) {
1526 // This fails if compatibility.ini is not there, so we'll
1527 // flush the caches on the next restart anyways.
1528 return NS_OK;
1531 nsAutoCString buf;
1532 rv = parser.GetString("Compatibility", "InvalidateCaches", buf);
1534 if (NS_FAILED(rv)) {
1535 PRFileDesc* fd;
1536 rv = file->OpenNSPRFileDesc(PR_RDWR | PR_APPEND, 0600, &fd);
1537 if (NS_FAILED(rv)) {
1538 NS_ERROR("could not create output stream");
1539 return NS_ERROR_NOT_AVAILABLE;
1541 static const char kInvalidationHeader[] =
1542 NS_LINEBREAK "InvalidateCaches=1" NS_LINEBREAK;
1543 PR_Write(fd, kInvalidationHeader, sizeof(kInvalidationHeader) - 1);
1544 PR_Close(fd);
1546 return NS_OK;
1549 NS_IMETHODIMP
1550 nsXULAppInfo::GetReplacedLockTime(PRTime* aReplacedLockTime) {
1551 if (!gProfileLock) return NS_ERROR_NOT_AVAILABLE;
1552 gProfileLock->GetReplacedLockTime(aReplacedLockTime);
1553 return NS_OK;
1556 NS_IMETHODIMP
1557 nsXULAppInfo::GetDefaultUpdateChannel(nsACString& aResult) {
1558 aResult.AssignLiteral(MOZ_STRINGIFY(MOZ_UPDATE_CHANNEL));
1559 return NS_OK;
1562 NS_IMETHODIMP
1563 nsXULAppInfo::GetDistributionID(nsACString& aResult) {
1564 aResult.AssignLiteral(MOZ_DISTRIBUTION_ID);
1565 return NS_OK;
1568 NS_IMETHODIMP
1569 nsXULAppInfo::GetWindowsDLLBlocklistStatus(bool* aResult) {
1570 #if defined(HAS_DLL_BLOCKLIST)
1571 *aResult = DllBlocklist_CheckStatus();
1572 #else
1573 *aResult = false;
1574 #endif
1575 return NS_OK;
1578 NS_IMETHODIMP
1579 nsXULAppInfo::GetRestartedByOS(bool* aResult) {
1580 *aResult = gRestartedByOS;
1581 return NS_OK;
1584 NS_IMETHODIMP
1585 nsXULAppInfo::GetChromeColorSchemeIsDark(bool* aResult) {
1586 PreferenceSheet::EnsureInitialized();
1587 *aResult = PreferenceSheet::ColorSchemeForChrome() == ColorScheme::Dark;
1588 return NS_OK;
1591 NS_IMETHODIMP
1592 nsXULAppInfo::GetContentThemeDerivedColorSchemeIsDark(bool* aResult) {
1593 *aResult =
1594 PreferenceSheet::ThemeDerivedColorSchemeForContent() == ColorScheme::Dark;
1595 return NS_OK;
1598 NS_IMETHODIMP
1599 nsXULAppInfo::GetPrefersReducedMotion(bool* aResult) {
1600 *aResult =
1601 LookAndFeel::GetInt(LookAndFeel::IntID::PrefersReducedMotion, 0) == 1;
1602 return NS_OK;
1605 NS_IMETHODIMP
1606 nsXULAppInfo::GetDrawInTitlebar(bool* aResult) {
1607 *aResult = LookAndFeel::DrawInTitlebar();
1608 return NS_OK;
1611 NS_IMETHODIMP
1612 nsXULAppInfo::GetDesktopEnvironment(nsACString& aDesktopEnvironment) {
1613 #ifdef MOZ_WIDGET_GTK
1614 aDesktopEnvironment.Assign(GetDesktopEnvironmentIdentifier());
1615 #endif
1616 return NS_OK;
1619 NS_IMETHODIMP
1620 nsXULAppInfo::GetIsWayland(bool* aResult) {
1621 #ifdef MOZ_WIDGET_GTK
1622 *aResult = GdkIsWaylandDisplay();
1623 #else
1624 *aResult = false;
1625 #endif
1626 return NS_OK;
1629 NS_IMETHODIMP
1630 nsXULAppInfo::GetProcessStartupShortcut(nsAString& aShortcut) {
1631 #if defined(XP_WIN)
1632 if (XRE_IsParentProcess()) {
1633 aShortcut.Assign(gProcessStartupShortcut);
1634 return NS_OK;
1636 #endif
1637 return NS_ERROR_NOT_AVAILABLE;
1640 #if defined(XP_WIN) && defined(MOZ_LAUNCHER_PROCESS)
1641 // Forward declaration
1642 void SetupLauncherProcessPref();
1644 static Maybe<LauncherRegistryInfo::EnabledState> gLauncherProcessState;
1645 #endif // defined(XP_WIN) && defined(MOZ_LAUNCHER_PROCESS)
1647 NS_IMETHODIMP
1648 nsXULAppInfo::GetLauncherProcessState(uint32_t* aResult) {
1649 #if defined(XP_WIN) && defined(MOZ_LAUNCHER_PROCESS)
1650 SetupLauncherProcessPref();
1652 if (!gLauncherProcessState) {
1653 return NS_ERROR_UNEXPECTED;
1656 *aResult = static_cast<uint32_t>(gLauncherProcessState.value());
1657 return NS_OK;
1658 #else
1659 return NS_ERROR_NOT_AVAILABLE;
1660 #endif
1663 #ifdef XP_WIN
1664 NS_IMETHODIMP
1665 nsXULAppInfo::GetUserCanElevate(bool* aUserCanElevate) {
1666 HANDLE rawToken;
1667 if (!::OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY, &rawToken)) {
1668 *aUserCanElevate = false;
1669 return NS_OK;
1672 nsAutoHandle token(rawToken);
1673 LauncherResult<TOKEN_ELEVATION_TYPE> elevationType = GetElevationType(token);
1674 if (elevationType.isErr()) {
1675 *aUserCanElevate = false;
1676 return NS_OK;
1679 // The possible values returned for elevationType and their meanings are:
1680 // TokenElevationTypeDefault: The token does not have a linked token
1681 // (e.g. UAC disabled or a standard user, so they can't be elevated)
1682 // TokenElevationTypeFull: The token is linked to an elevated token
1683 // (e.g. UAC is enabled and the user is already elevated so they can't
1684 // be elevated again)
1685 // TokenElevationTypeLimited: The token is linked to a limited token
1686 // (e.g. UAC is enabled and the user is not elevated, so they can be
1687 // elevated)
1688 *aUserCanElevate = (elevationType.inspect() == TokenElevationTypeLimited);
1689 return NS_OK;
1691 #endif
1693 NS_IMETHODIMP
1694 nsXULAppInfo::GetCrashReporterEnabled(bool* aEnabled) {
1695 *aEnabled = CrashReporter::GetEnabled();
1696 return NS_OK;
1699 NS_IMETHODIMP
1700 nsXULAppInfo::SetEnabled(bool aEnabled) {
1701 if (aEnabled) {
1702 if (CrashReporter::GetEnabled()) {
1703 // no point in erroring for double-enabling
1704 return NS_OK;
1707 nsCOMPtr<nsIFile> greBinDir;
1708 NS_GetSpecialDirectory(NS_GRE_BIN_DIR, getter_AddRefs(greBinDir));
1709 if (!greBinDir) {
1710 return NS_ERROR_FAILURE;
1713 nsCOMPtr<nsIFile> xreBinDirectory = greBinDir;
1714 if (!xreBinDirectory) {
1715 return NS_ERROR_FAILURE;
1718 return CrashReporter::SetExceptionHandler(xreBinDirectory, true);
1721 if (!CrashReporter::GetEnabled()) {
1722 // no point in erroring for double-disabling
1723 return NS_OK;
1726 return CrashReporter::UnsetExceptionHandler();
1729 NS_IMETHODIMP
1730 nsXULAppInfo::GetServerURL(nsIURL** aServerURL) {
1731 NS_ENSURE_ARG_POINTER(aServerURL);
1732 if (!CrashReporter::GetEnabled()) return NS_ERROR_NOT_INITIALIZED;
1734 nsAutoCString data;
1735 if (!CrashReporter::GetServerURL(data)) {
1736 return NS_ERROR_FAILURE;
1738 nsCOMPtr<nsIURI> uri;
1739 NS_NewURI(getter_AddRefs(uri), data);
1740 if (!uri) return NS_ERROR_FAILURE;
1742 nsCOMPtr<nsIURL> url;
1743 url = do_QueryInterface(uri);
1744 NS_ADDREF(*aServerURL = url);
1746 return NS_OK;
1749 NS_IMETHODIMP
1750 nsXULAppInfo::SetServerURL(nsIURL* aServerURL) {
1751 // Only allow https or http URLs
1752 if (!aServerURL->SchemeIs("http") && !aServerURL->SchemeIs("https")) {
1753 return NS_ERROR_INVALID_ARG;
1756 nsAutoCString spec;
1757 nsresult rv = aServerURL->GetSpec(spec);
1758 NS_ENSURE_SUCCESS(rv, rv);
1760 return CrashReporter::SetServerURL(spec);
1763 NS_IMETHODIMP
1764 nsXULAppInfo::GetMinidumpPath(nsIFile** aMinidumpPath) {
1765 if (!CrashReporter::GetEnabled()) return NS_ERROR_NOT_INITIALIZED;
1767 nsAutoString path;
1768 if (!CrashReporter::GetMinidumpPath(path)) return NS_ERROR_FAILURE;
1770 nsresult rv = NS_NewLocalFile(path, false, aMinidumpPath);
1771 NS_ENSURE_SUCCESS(rv, rv);
1772 return NS_OK;
1775 NS_IMETHODIMP
1776 nsXULAppInfo::SetMinidumpPath(nsIFile* aMinidumpPath) {
1777 nsAutoString path;
1778 nsresult rv = aMinidumpPath->GetPath(path);
1779 NS_ENSURE_SUCCESS(rv, rv);
1780 return CrashReporter::SetMinidumpPath(path);
1783 NS_IMETHODIMP
1784 nsXULAppInfo::GetMinidumpForID(const nsAString& aId, nsIFile** aMinidump) {
1785 if (!CrashReporter::GetMinidumpForID(aId, aMinidump)) {
1786 return NS_ERROR_FILE_NOT_FOUND;
1789 return NS_OK;
1792 NS_IMETHODIMP
1793 nsXULAppInfo::GetExtraFileForID(const nsAString& aId, nsIFile** aExtraFile) {
1794 if (!CrashReporter::GetExtraFileForID(aId, aExtraFile)) {
1795 return NS_ERROR_FILE_NOT_FOUND;
1798 return NS_OK;
1801 NS_IMETHODIMP
1802 nsXULAppInfo::AnnotateCrashReport(const nsACString& key,
1803 const nsACString& data) {
1804 CrashReporter::Annotation annotation;
1806 if (!AnnotationFromString(annotation, PromiseFlatCString(key).get())) {
1807 return NS_ERROR_INVALID_ARG;
1810 CrashReporter::RecordAnnotationNSCString(annotation, data);
1811 return NS_OK;
1814 NS_IMETHODIMP
1815 nsXULAppInfo::RemoveCrashReportAnnotation(const nsACString& key) {
1816 CrashReporter::Annotation annotation;
1818 if (!AnnotationFromString(annotation, PromiseFlatCString(key).get())) {
1819 return NS_ERROR_INVALID_ARG;
1822 CrashReporter::UnrecordAnnotation(annotation);
1823 return NS_OK;
1826 NS_IMETHODIMP
1827 nsXULAppInfo::IsAnnotationAllowedForPing(const nsACString& aValue,
1828 bool* aIsAllowed) {
1829 CrashReporter::Annotation annotation;
1831 if (!AnnotationFromString(annotation, PromiseFlatCString(aValue).get())) {
1832 return NS_ERROR_INVALID_ARG;
1835 *aIsAllowed = CrashReporter::IsAnnotationAllowedForPing(annotation);
1837 return NS_OK;
1840 NS_IMETHODIMP
1841 nsXULAppInfo::AppendAppNotesToCrashReport(const nsACString& data) {
1842 return CrashReporter::AppendAppNotesToCrashReport(data);
1845 NS_IMETHODIMP
1846 nsXULAppInfo::RegisterAppMemory(uint64_t pointer, uint64_t len) {
1847 return CrashReporter::RegisterAppMemory((void*)pointer, len);
1850 NS_IMETHODIMP
1851 nsXULAppInfo::WriteMinidumpForException(void* aExceptionInfo) {
1852 #ifdef XP_WIN
1853 return CrashReporter::WriteMinidumpForException(
1854 static_cast<EXCEPTION_POINTERS*>(aExceptionInfo));
1855 #else
1856 return NS_ERROR_NOT_IMPLEMENTED;
1857 #endif
1860 NS_IMETHODIMP
1861 nsXULAppInfo::AppendObjCExceptionInfoToAppNotes(void* aException) {
1862 #ifdef XP_MACOSX
1863 return CrashReporter::AppendObjCExceptionInfoToAppNotes(aException);
1864 #else
1865 return NS_ERROR_NOT_IMPLEMENTED;
1866 #endif
1869 NS_IMETHODIMP
1870 nsXULAppInfo::GetSubmitReports(bool* aEnabled) {
1871 return CrashReporter::GetSubmitReports(aEnabled);
1874 NS_IMETHODIMP
1875 nsXULAppInfo::SetSubmitReports(bool aEnabled) {
1876 return CrashReporter::SetSubmitReports(aEnabled);
1879 NS_IMETHODIMP
1880 nsXULAppInfo::UpdateCrashEventsDir() {
1881 CrashReporter::UpdateCrashEventsDir();
1882 return NS_OK;
1885 NS_IMETHODIMP
1886 nsXULAppInfo::SaveMemoryReport() {
1887 if (!CrashReporter::GetEnabled()) {
1888 return NS_ERROR_NOT_INITIALIZED;
1890 nsCOMPtr<nsIFile> file;
1891 nsresult rv = CrashReporter::GetDefaultMemoryReportFile(getter_AddRefs(file));
1892 if (NS_WARN_IF(NS_FAILED(rv))) {
1893 return rv;
1896 nsString path;
1897 file->GetPath(path);
1899 nsCOMPtr<nsIMemoryInfoDumper> dumper =
1900 do_GetService("@mozilla.org/memory-info-dumper;1");
1901 if (NS_WARN_IF(!dumper)) {
1902 return NS_ERROR_UNEXPECTED;
1905 rv = dumper->DumpMemoryReportsToNamedFile(
1906 path, this, file, true /* anonymize */, false /* minimizeMemoryUsage */);
1907 if (NS_WARN_IF(NS_FAILED(rv))) {
1908 return rv;
1910 return NS_OK;
1913 // This method is from nsIFInishDumpingCallback.
1914 NS_IMETHODIMP
1915 nsXULAppInfo::Callback(nsISupports* aData) {
1916 nsCOMPtr<nsIFile> file = do_QueryInterface(aData);
1917 MOZ_ASSERT(file);
1919 CrashReporter::SetMemoryReportFile(file);
1920 return NS_OK;
1923 static const nsXULAppInfo kAppInfo;
1924 namespace mozilla {
1925 nsresult AppInfoConstructor(REFNSIID aIID, void** aResult) {
1926 return const_cast<nsXULAppInfo*>(&kAppInfo)->QueryInterface(aIID, aResult);
1928 } // namespace mozilla
1930 bool gLogConsoleErrors = false;
1932 #define NS_ENSURE_TRUE_LOG(x, ret) \
1933 PR_BEGIN_MACRO \
1934 if (MOZ_UNLIKELY(!(x))) { \
1935 NS_WARNING("NS_ENSURE_TRUE(" #x ") failed"); \
1936 gLogConsoleErrors = true; \
1937 return ret; \
1939 PR_END_MACRO
1941 #define NS_ENSURE_SUCCESS_LOG(res, ret) \
1942 NS_ENSURE_TRUE_LOG(NS_SUCCEEDED(res), ret)
1945 * Because we're starting/stopping XPCOM several times in different scenarios,
1946 * this class is a stack-based critter that makes sure that XPCOM is shut down
1947 * during early returns.
1950 class ScopedXPCOMStartup {
1951 public:
1952 ScopedXPCOMStartup() : mServiceManager(nullptr) {}
1953 ~ScopedXPCOMStartup();
1955 nsresult Initialize(bool aInitJSContext = true);
1956 nsresult SetWindowCreator(nsINativeAppSupport* native);
1958 private:
1959 nsIServiceManager* mServiceManager;
1960 static nsINativeAppSupport* gNativeAppSupport;
1962 friend already_AddRefed<nsINativeAppSupport> NS_GetNativeAppSupport();
1965 ScopedXPCOMStartup::~ScopedXPCOMStartup() {
1966 NS_IF_RELEASE(gNativeAppSupport);
1968 if (mServiceManager) {
1969 #ifdef XP_MACOSX
1970 // On OS X, we need a pool to catch cocoa objects that are autoreleased
1971 // during teardown.
1972 mozilla::MacAutoreleasePool pool;
1973 #endif
1975 nsCOMPtr<nsIAppStartup> appStartup(components::AppStartup::Service());
1976 if (appStartup) appStartup->DestroyHiddenWindow();
1978 gDirServiceProvider->DoShutdown();
1979 PROFILER_MARKER_UNTYPED("Shutdown early", OTHER);
1981 WriteConsoleLog();
1983 NS_ShutdownXPCOM(mServiceManager);
1984 mServiceManager = nullptr;
1988 nsresult ScopedXPCOMStartup::Initialize(bool aInitJSContext) {
1989 NS_ASSERTION(gDirServiceProvider, "Should not get here!");
1991 nsresult rv;
1993 rv = NS_InitXPCOM(&mServiceManager, gDirServiceProvider->GetAppDir(),
1994 gDirServiceProvider, aInitJSContext);
1995 if (NS_FAILED(rv)) {
1996 NS_ERROR("Couldn't start xpcom!");
1997 mServiceManager = nullptr;
1998 } else {
1999 #ifdef DEBUG
2000 nsCOMPtr<nsIComponentRegistrar> reg = do_QueryInterface(mServiceManager);
2001 NS_ASSERTION(reg, "Service Manager doesn't QI to Registrar.");
2002 #endif
2005 return rv;
2009 * This is a little factory class that serves as a singleton-service-factory
2010 * for the nativeappsupport object.
2012 class nsSingletonFactory final : public nsIFactory {
2013 public:
2014 NS_DECL_ISUPPORTS
2015 NS_DECL_NSIFACTORY
2017 explicit nsSingletonFactory(nsISupports* aSingleton);
2019 private:
2020 ~nsSingletonFactory() = default;
2021 nsCOMPtr<nsISupports> mSingleton;
2024 nsSingletonFactory::nsSingletonFactory(nsISupports* aSingleton)
2025 : mSingleton(aSingleton) {
2026 NS_ASSERTION(mSingleton, "Singleton was null!");
2029 NS_IMPL_ISUPPORTS(nsSingletonFactory, nsIFactory)
2031 NS_IMETHODIMP
2032 nsSingletonFactory::CreateInstance(const nsIID& aIID, void** aResult) {
2033 return mSingleton->QueryInterface(aIID, aResult);
2037 * Set our windowcreator on the WindowWatcher service.
2039 nsresult ScopedXPCOMStartup::SetWindowCreator(nsINativeAppSupport* native) {
2040 nsresult rv;
2042 NS_IF_ADDREF(gNativeAppSupport = native);
2044 nsCOMPtr<nsIWindowCreator> creator(components::AppStartup::Service());
2045 if (!creator) return NS_ERROR_UNEXPECTED;
2047 nsCOMPtr<nsIWindowWatcher> wwatch(
2048 do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv));
2049 NS_ENSURE_SUCCESS(rv, rv);
2051 return wwatch->SetWindowCreator(creator);
2054 /* static */ already_AddRefed<nsINativeAppSupport> NS_GetNativeAppSupport() {
2055 if (!ScopedXPCOMStartup::gNativeAppSupport) {
2056 return nullptr;
2059 return do_AddRef(ScopedXPCOMStartup::gNativeAppSupport);
2062 nsINativeAppSupport* ScopedXPCOMStartup::gNativeAppSupport;
2064 static void DumpArbitraryHelp() {
2065 nsresult rv;
2067 ScopedLogging log;
2070 ScopedXPCOMStartup xpcom;
2071 xpcom.Initialize();
2073 nsCOMPtr<nsICommandLineRunner> cmdline(new nsCommandLine());
2075 nsCString text;
2076 rv = cmdline->GetHelpText(text);
2077 if (NS_SUCCEEDED(rv)) printf("%s", text.get());
2081 // English text needs to go into a dtd file.
2082 // But when this is called we have no components etc. These strings must either
2083 // be here, or in a native resource file.
2084 static void DumpHelp() {
2085 printf(
2086 "Usage: %s [ options ... ] [URL]\n"
2087 " where options include:\n\n",
2088 gArgv[0]);
2090 #ifdef MOZ_X11
2091 printf(
2092 "X11 options\n"
2093 " --display=DISPLAY X display to use\n"
2094 " --sync Make X calls synchronous\n");
2095 #endif
2096 #ifdef XP_UNIX
2097 printf(
2098 " --g-fatal-warnings Make all warnings fatal\n"
2099 "\n%s options\n",
2100 (const char*)gAppData->name);
2101 #endif
2103 printf(
2104 " -h or --help Print this message.\n"
2105 " -v or --version Print %s version.\n"
2106 " --full-version Print %s version, build and platform build ids.\n"
2107 " -P <profile> Start with <profile>.\n"
2108 " --profile <path> Start with profile at <path>.\n"
2109 " --migration Start with migration wizard.\n"
2110 " --ProfileManager Start with ProfileManager.\n"
2111 #ifdef MOZ_HAS_REMOTE
2112 " --no-remote Do not accept or send remote commands; implies\n"
2113 " --new-instance.\n"
2114 " --new-instance Open new instance, not a new window in running "
2115 "instance.\n"
2116 #endif
2117 " --safe-mode Disables extensions and themes for this session.\n"
2118 #ifdef MOZ_BLOCK_PROFILE_DOWNGRADE
2119 " --allow-downgrade Allows downgrading a profile.\n"
2120 #endif
2121 " --MOZ_LOG=<modules> Treated as MOZ_LOG=<modules> environment "
2122 "variable,\n"
2123 " overrides it.\n"
2124 " --MOZ_LOG_FILE=<file> Treated as MOZ_LOG_FILE=<file> environment "
2125 "variable,\n"
2126 " overrides it. If MOZ_LOG_FILE is not specified as "
2127 "an\n"
2128 " argument or as an environment variable, logging "
2129 "will be\n"
2130 " written to stdout.\n",
2131 (const char*)gAppData->name, (const char*)gAppData->name);
2133 #if defined(XP_WIN)
2134 printf(" --console Start %s with a debugging console.\n",
2135 (const char*)gAppData->name);
2136 #endif
2138 #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) || defined(XP_MACOSX)
2139 printf(" --headless Run without a GUI.\n");
2140 #endif
2142 // this works, but only after the components have registered. so if you drop
2143 // in a new command line handler, --help won't not until the second run. out
2144 // of the bug, because we ship a component.reg file, it works correctly.
2145 DumpArbitraryHelp();
2148 static inline void DumpVersion() {
2149 if (gAppData->vendor && *gAppData->vendor) {
2150 printf("%s ", (const char*)gAppData->vendor);
2152 printf("%s ", (const char*)gAppData->name);
2154 // Use the displayed version
2155 // For example, for beta, we would display 42.0b2 instead of 42.0
2156 printf("%s", MOZ_STRINGIFY(MOZ_APP_VERSION_DISPLAY));
2158 if (gAppData->copyright && *gAppData->copyright) {
2159 printf(", %s", (const char*)gAppData->copyright);
2161 printf("\n");
2164 static inline void DumpFullVersion() {
2165 if (gAppData->vendor && *gAppData->vendor) {
2166 printf("%s ", (const char*)gAppData->vendor);
2168 printf("%s ", (const char*)gAppData->name);
2170 // Use the displayed version
2171 // For example, for beta, we would display 42.0b2 instead of 42.0
2172 printf("%s ", MOZ_STRINGIFY(MOZ_APP_VERSION_DISPLAY));
2174 printf("%s ", (const char*)gAppData->buildID);
2175 printf("%s ", (const char*)PlatformBuildID());
2176 if (gAppData->copyright && *gAppData->copyright) {
2177 printf(", %s", (const char*)gAppData->copyright);
2179 printf("\n");
2182 void XRE_InitOmnijar(nsIFile* greOmni, nsIFile* appOmni) {
2183 mozilla::Omnijar::Init(greOmni, appOmni);
2186 nsresult XRE_GetBinaryPath(nsIFile** aResult) {
2187 return mozilla::BinaryPath::GetFile(aResult);
2190 #ifdef XP_WIN
2191 # include "nsWindowsRestart.cpp"
2192 # include <shellapi.h>
2194 typedef BOOL(WINAPI* SetProcessDEPPolicyFunc)(DWORD dwFlags);
2196 static void RegisterApplicationRestartChanged(const char* aPref, void* aData) {
2197 DWORD cchCmdLine = 0;
2198 HRESULT rc = ::GetApplicationRestartSettings(::GetCurrentProcess(), nullptr,
2199 &cchCmdLine, nullptr);
2200 bool wasRegistered = false;
2201 if (rc == S_OK) {
2202 wasRegistered = true;
2205 if (Preferences::GetBool(PREF_WIN_REGISTER_APPLICATION_RESTART, false) &&
2206 !wasRegistered) {
2207 // Make the command line to use when restarting.
2208 // Excludes argv[0] because RegisterApplicationRestart adds the
2209 // executable name, replace that temporarily with -os-restarted
2210 char* exeName = gRestartArgv[0];
2211 gRestartArgv[0] = const_cast<char*>("-os-restarted");
2212 wchar_t** restartArgvConverted =
2213 AllocConvertUTF8toUTF16Strings(gRestartArgc, gRestartArgv);
2214 gRestartArgv[0] = exeName;
2216 mozilla::UniquePtr<wchar_t[]> restartCommandLine;
2217 if (restartArgvConverted) {
2218 restartCommandLine =
2219 mozilla::MakeCommandLine(gRestartArgc, restartArgvConverted);
2220 FreeAllocStrings(gRestartArgc, restartArgvConverted);
2223 if (restartCommandLine) {
2224 // Flags RESTART_NO_PATCH and RESTART_NO_REBOOT are not set, so we
2225 // should be restarted if terminated by an update or restart.
2226 ::RegisterApplicationRestart(restartCommandLine.get(),
2227 RESTART_NO_CRASH | RESTART_NO_HANG);
2229 } else if (wasRegistered) {
2230 ::UnregisterApplicationRestart();
2234 static void OnAlteredPrefetchPrefChanged(const char* aPref, void* aData) {
2235 int32_t prefVal = Preferences::GetInt(PREF_WIN_ALTERED_DLL_PREFETCH, 0);
2237 mozilla::DllPrefetchExperimentRegistryInfo prefetchRegInfo;
2238 mozilla::DebugOnly<mozilla::Result<Ok, nsresult>> reflectResult =
2239 prefetchRegInfo.ReflectPrefToRegistry(prefVal);
2241 MOZ_ASSERT(reflectResult.value.isOk());
2244 static void SetupAlteredPrefetchPref() {
2245 mozilla::DllPrefetchExperimentRegistryInfo prefetchRegInfo;
2247 mozilla::DebugOnly<mozilla::Result<Ok, nsresult>> reflectResult =
2248 prefetchRegInfo.ReflectPrefToRegistry(
2249 Preferences::GetInt(PREF_WIN_ALTERED_DLL_PREFETCH, 0));
2250 MOZ_ASSERT(reflectResult.value.isOk());
2252 Preferences::RegisterCallback(&OnAlteredPrefetchPrefChanged,
2253 PREF_WIN_ALTERED_DLL_PREFETCH);
2256 static void ReflectSkeletonUIPrefToRegistry(const char* aPref, void* aData) {
2257 Unused << aPref;
2258 Unused << aData;
2260 bool shouldBeEnabled =
2261 Preferences::GetBool(kPrefPreXulSkeletonUI, false) &&
2262 Preferences::GetBool(kPrefBrowserStartupBlankWindow, false) &&
2263 LookAndFeel::DrawInTitlebar();
2264 if (shouldBeEnabled && Preferences::HasUserValue(kPrefThemeId)) {
2265 nsCString themeId;
2266 Preferences::GetCString(kPrefThemeId, themeId);
2267 if (themeId.EqualsLiteral("default-theme@mozilla.org")) {
2268 Unused << SetPreXULSkeletonUIThemeId(ThemeMode::Default);
2269 } else if (themeId.EqualsLiteral("firefox-compact-dark@mozilla.org")) {
2270 Unused << SetPreXULSkeletonUIThemeId(ThemeMode::Dark);
2271 } else if (themeId.EqualsLiteral("firefox-compact-light@mozilla.org")) {
2272 Unused << SetPreXULSkeletonUIThemeId(ThemeMode::Light);
2273 } else {
2274 shouldBeEnabled = false;
2276 } else if (shouldBeEnabled) {
2277 Unused << SetPreXULSkeletonUIThemeId(ThemeMode::Default);
2280 if (GetPreXULSkeletonUIEnabled() != shouldBeEnabled) {
2281 Unused << SetPreXULSkeletonUIEnabledIfAllowed(shouldBeEnabled);
2285 static void SetupSkeletonUIPrefs() {
2286 ReflectSkeletonUIPrefToRegistry(nullptr, nullptr);
2287 Preferences::RegisterCallback(&ReflectSkeletonUIPrefToRegistry,
2288 kPrefPreXulSkeletonUI);
2289 Preferences::RegisterCallback(&ReflectSkeletonUIPrefToRegistry,
2290 kPrefBrowserStartupBlankWindow);
2291 Preferences::RegisterCallback(&ReflectSkeletonUIPrefToRegistry, kPrefThemeId);
2292 Preferences::RegisterCallback(
2293 &ReflectSkeletonUIPrefToRegistry,
2294 nsDependentCString(StaticPrefs::GetPrefName_browser_tabs_inTitlebar()));
2297 # if defined(MOZ_LAUNCHER_PROCESS)
2299 static void OnLauncherPrefChanged(const char* aPref, void* aData) {
2300 bool prefVal = Preferences::GetBool(PREF_WIN_LAUNCHER_PROCESS_ENABLED, true);
2302 mozilla::LauncherRegistryInfo launcherRegInfo;
2303 mozilla::DebugOnly<mozilla::LauncherVoidResult> reflectResult =
2304 launcherRegInfo.ReflectPrefToRegistry(prefVal);
2305 MOZ_ASSERT(reflectResult.inspect().isOk());
2308 static void OnLauncherTelemetryPrefChanged(const char* aPref, void* aData) {
2309 bool prefVal = Preferences::GetBool(kPrefHealthReportUploadEnabled, true);
2311 mozilla::LauncherRegistryInfo launcherRegInfo;
2312 mozilla::DebugOnly<mozilla::LauncherVoidResult> reflectResult =
2313 launcherRegInfo.ReflectTelemetryPrefToRegistry(prefVal);
2314 MOZ_ASSERT(reflectResult.inspect().isOk());
2317 static void SetupLauncherProcessPref() {
2318 if (gLauncherProcessState) {
2319 // We've already successfully run
2320 return;
2323 mozilla::LauncherRegistryInfo launcherRegInfo;
2325 mozilla::LauncherResult<mozilla::LauncherRegistryInfo::EnabledState>
2326 enabledState = launcherRegInfo.IsEnabled();
2328 if (enabledState.isOk()) {
2329 gLauncherProcessState = Some(enabledState.unwrap());
2331 CrashReporter::RecordAnnotationU32(
2332 CrashReporter::Annotation::LauncherProcessState,
2333 static_cast<uint32_t>(enabledState.unwrap()));
2335 // Reflect the launcher process registry state into user prefs
2336 Preferences::SetBool(
2337 PREF_WIN_LAUNCHER_PROCESS_ENABLED,
2338 enabledState.unwrap() !=
2339 mozilla::LauncherRegistryInfo::EnabledState::ForceDisabled);
2342 mozilla::DebugOnly<mozilla::LauncherVoidResult> reflectResult =
2343 launcherRegInfo.ReflectTelemetryPrefToRegistry(
2344 Preferences::GetBool(kPrefHealthReportUploadEnabled, true));
2345 MOZ_ASSERT(reflectResult.inspect().isOk());
2347 Preferences::RegisterCallback(&OnLauncherPrefChanged,
2348 PREF_WIN_LAUNCHER_PROCESS_ENABLED);
2349 Preferences::RegisterCallback(&OnLauncherTelemetryPrefChanged,
2350 kPrefHealthReportUploadEnabled);
2353 # endif // defined(MOZ_LAUNCHER_PROCESS)
2355 # if defined(MOZ_DEFAULT_BROWSER_AGENT)
2357 # define DEFAULT_BROWSER_AGENT_KEY_NAME \
2358 "SOFTWARE\\" MOZ_APP_VENDOR "\\" MOZ_APP_NAME "\\Default Browser Agent"
2360 static nsresult PrependRegistryValueName(nsAutoString& aValueName) {
2361 nsresult rv;
2363 nsCOMPtr<nsIFile> binaryPath;
2364 rv = XRE_GetBinaryPath(getter_AddRefs(binaryPath));
2365 NS_ENSURE_SUCCESS(rv, rv);
2367 nsCOMPtr<nsIFile> binaryDir;
2368 rv = binaryPath->GetParent(getter_AddRefs(binaryDir));
2369 NS_ENSURE_SUCCESS(rv, rv);
2371 nsAutoString prefix;
2372 rv = binaryDir->GetPath(prefix);
2373 NS_ENSURE_SUCCESS(rv, rv);
2375 prefix.AppendLiteral("|");
2376 aValueName.Insert(prefix, 0);
2378 return NS_OK;
2381 static void OnDefaultAgentTelemetryPrefChanged(const char* aPref, void* aData) {
2382 nsresult rv;
2383 nsAutoString valueName;
2384 if (strcmp(aPref, kPrefHealthReportUploadEnabled) == 0) {
2385 valueName.AssignLiteral("DisableTelemetry");
2386 } else if (strcmp(aPref, kPrefDefaultAgentEnabled) == 0) {
2387 valueName.AssignLiteral("DisableDefaultBrowserAgent");
2388 } else {
2389 return;
2391 rv = PrependRegistryValueName(valueName);
2392 NS_ENSURE_SUCCESS_VOID(rv);
2394 nsCOMPtr<nsIWindowsRegKey> regKey =
2395 do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv);
2396 NS_ENSURE_SUCCESS_VOID(rv);
2398 nsAutoString keyName;
2399 keyName.AppendLiteral(DEFAULT_BROWSER_AGENT_KEY_NAME);
2400 rv = regKey->Create(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER, keyName,
2401 nsIWindowsRegKey::ACCESS_WRITE);
2403 bool prefVal = Preferences::GetBool(aPref, true);
2405 // We're recording whether the pref is *disabled*, so invert the value.
2406 rv = regKey->WriteIntValue(valueName, prefVal ? 0 : 1);
2407 NS_ENSURE_SUCCESS_VOID(rv);
2410 static void OnSetDefaultBrowserUserChoicePrefChanged(const char* aPref,
2411 void* aData) {
2412 nsresult rv;
2413 if (strcmp(aPref, kPrefSetDefaultBrowserUserChoicePref) != 0) {
2414 return;
2416 nsAutoString valueName;
2417 valueName.AssignLiteral("SetDefaultBrowserUserChoice");
2418 rv = PrependRegistryValueName(valueName);
2419 NS_ENSURE_SUCCESS_VOID(rv);
2421 nsCOMPtr<nsIWindowsRegKey> regKey =
2422 do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv);
2423 NS_ENSURE_SUCCESS_VOID(rv);
2425 nsAutoString keyName;
2426 keyName.AppendLiteral(DEFAULT_BROWSER_AGENT_KEY_NAME);
2427 rv = regKey->Create(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER, keyName,
2428 nsIWindowsRegKey::ACCESS_WRITE);
2430 bool prefVal = Preferences::GetBool(aPref, true);
2432 rv = regKey->WriteIntValue(valueName, prefVal);
2433 NS_ENSURE_SUCCESS_VOID(rv);
2436 static void OnDefaultAgentRemoteSettingsPrefChanged(const char* aPref,
2437 void* aData) {
2438 nsresult rv;
2439 nsAutoString valueName;
2440 if (strcmp(aPref, kPrefServicesSettingsServer) == 0) {
2441 valueName.AssignLiteral("ServicesSettingsServer");
2442 } else {
2443 return;
2445 rv = PrependRegistryValueName(valueName);
2446 NS_ENSURE_SUCCESS_VOID(rv);
2448 nsCOMPtr<nsIWindowsRegKey> regKey =
2449 do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv);
2450 NS_ENSURE_SUCCESS_VOID(rv);
2452 nsAutoString keyName;
2453 keyName.AppendLiteral(DEFAULT_BROWSER_AGENT_KEY_NAME);
2454 rv = regKey->Create(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER, keyName,
2455 nsIWindowsRegKey::ACCESS_WRITE);
2457 NS_ENSURE_SUCCESS_VOID(rv);
2459 nsAutoString prefVal;
2460 rv = Preferences::GetString(aPref, prefVal);
2461 if (NS_FAILED(rv)) {
2462 return;
2465 if (prefVal.IsEmpty()) {
2466 rv = regKey->RemoveValue(valueName);
2467 } else {
2468 rv = regKey->WriteStringValue(valueName, prefVal);
2470 NS_ENSURE_SUCCESS_VOID(rv);
2473 static void SetDefaultAgentLastRunTime() {
2474 nsresult rv;
2475 nsAutoString valueName;
2476 valueName.AppendLiteral("AppLastRunTime");
2477 rv = PrependRegistryValueName(valueName);
2478 NS_ENSURE_SUCCESS_VOID(rv);
2480 nsCOMPtr<nsIWindowsRegKey> regKey =
2481 do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv);
2482 NS_ENSURE_SUCCESS_VOID(rv);
2484 nsAutoString keyName;
2485 keyName.AppendLiteral(DEFAULT_BROWSER_AGENT_KEY_NAME);
2486 rv = regKey->Create(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER, keyName,
2487 nsIWindowsRegKey::ACCESS_WRITE);
2488 NS_ENSURE_SUCCESS_VOID(rv);
2490 FILETIME fileTime;
2491 GetSystemTimeAsFileTime(&fileTime);
2493 ULARGE_INTEGER integerTime;
2494 integerTime.u.LowPart = fileTime.dwLowDateTime;
2495 integerTime.u.HighPart = fileTime.dwHighDateTime;
2497 rv = regKey->WriteInt64Value(valueName, integerTime.QuadPart);
2498 NS_ENSURE_SUCCESS_VOID(rv);
2501 # endif // defined(MOZ_DEFAULT_BROWSER_AGENT)
2503 #endif // XP_WIN
2505 void UnlockProfile() {
2506 if (gProfileLock) {
2507 gProfileLock->Unlock();
2511 nsresult LaunchChild(bool aBlankCommandLine, bool aTryExec) {
2512 // Restart this process by exec'ing it into the current process
2513 // if supported by the platform. Otherwise, use NSPR.
2515 #ifdef MOZ_JPROF
2516 // make sure JPROF doesn't think we're E10s
2517 unsetenv("JPROF_ISCHILD");
2518 #endif
2520 if (aBlankCommandLine) {
2521 gRestartArgc = 1;
2522 gRestartArgv[gRestartArgc] = nullptr;
2525 #if defined(MOZ_HAS_REMOTE)
2526 if (gRestartWithoutRemote) {
2527 SaveToEnv("MOZ_NO_REMOTE=1");
2529 #endif
2531 SaveToEnv("MOZ_LAUNCHED_CHILD=1");
2532 #if defined(MOZ_LAUNCHER_PROCESS)
2533 SaveToEnv("MOZ_LAUNCHER_PROCESS=1");
2534 #endif // defined(MOZ_LAUNCHER_PROCESS)
2536 #if !defined(MOZ_WIDGET_ANDROID) // Android has separate restart code.
2537 # if defined(XP_MACOSX)
2538 InitializeMacApp();
2539 CommandLineServiceMac::SetupMacCommandLine(gRestartArgc, gRestartArgv, true);
2540 LaunchChildMac(gRestartArgc, gRestartArgv);
2541 # else
2542 nsCOMPtr<nsIFile> lf;
2543 nsresult rv = XRE_GetBinaryPath(getter_AddRefs(lf));
2544 if (NS_FAILED(rv)) return rv;
2546 # if defined(XP_WIN)
2547 nsAutoString exePath;
2548 rv = lf->GetPath(exePath);
2549 if (NS_FAILED(rv)) return rv;
2551 HANDLE hProcess;
2552 if (!WinLaunchChild(exePath.get(), gRestartArgc, gRestartArgv, nullptr,
2553 &hProcess))
2554 return NS_ERROR_FAILURE;
2555 // Keep the current process around until the restarted process has created
2556 // its message queue, to avoid the launched process's windows being forced
2557 // into the background.
2558 mozilla::WaitForInputIdle(hProcess);
2559 ::CloseHandle(hProcess);
2561 # else
2562 nsAutoCString exePath;
2563 rv = lf->GetNativePath(exePath);
2564 if (NS_FAILED(rv)) return rv;
2566 # if defined(XP_UNIX)
2567 if (aTryExec) {
2568 execv(exePath.get(), gRestartArgv);
2570 // If execv returns we know it's because it failed.
2571 return NS_ERROR_FAILURE;
2573 # endif
2574 if (PR_CreateProcessDetached(exePath.get(), gRestartArgv, nullptr, nullptr) ==
2575 PR_FAILURE) {
2576 return NS_ERROR_FAILURE;
2579 // Note that we don't know if the child process starts okay, if it
2580 // immediately returns non-zero then we may mask that by returning a zero
2581 // exit status.
2583 # endif // WP_WIN
2584 # endif // WP_MACOSX
2585 #endif // MOZ_WIDGET_ANDROID
2587 return NS_ERROR_LAUNCHED_CHILD_PROCESS;
2590 static const char kProfileProperties[] =
2591 "chrome://mozapps/locale/profile/profileSelection.properties";
2593 namespace {
2596 * This class, instead of a raw nsresult, should be the return type of any
2597 * function called by SelectProfile that initializes XPCOM.
2599 class ReturnAbortOnError {
2600 public:
2601 MOZ_IMPLICIT ReturnAbortOnError(nsresult aRv) { mRv = ConvertRv(aRv); }
2603 operator nsresult() { return mRv; }
2605 private:
2606 inline nsresult ConvertRv(nsresult aRv) {
2607 if (NS_SUCCEEDED(aRv) || aRv == NS_ERROR_LAUNCHED_CHILD_PROCESS) {
2608 return aRv;
2610 #ifdef MOZ_BACKGROUNDTASKS
2611 // A background task that fails to lock its profile will return
2612 // NS_ERROR_UNEXPECTED and this will allow the task to exit with a
2613 // non-zero exit code.
2614 if (aRv == NS_ERROR_UNEXPECTED && BackgroundTasks::IsBackgroundTaskMode()) {
2615 return aRv;
2617 #endif
2618 return NS_ERROR_ABORT;
2621 nsresult mRv;
2624 } // namespace
2626 static nsresult ProfileMissingDialog(nsINativeAppSupport* aNative) {
2627 #ifdef MOZ_WIDGET_ANDROID
2628 // We cannot really do anything this early during initialization, so we just
2629 // return as this is likely the effect of misconfiguration on the test side.
2630 // Non-test code paths cannot set the profile folder, which is always the
2631 // default one.
2632 Output(true, "Could not find profile folder.\n");
2633 return NS_ERROR_ABORT;
2634 #else
2635 # ifdef MOZ_BACKGROUNDTASKS
2636 if (BackgroundTasks::IsBackgroundTaskMode()) {
2637 // We should never get to this point in background task mode.
2638 Output(false,
2639 "Could not determine any profile running in backgroundtask mode!\n");
2640 return NS_ERROR_ABORT;
2642 # endif // MOZ_BACKGROUNDTASKS
2644 nsresult rv;
2646 ScopedXPCOMStartup xpcom;
2647 rv = xpcom.Initialize();
2648 NS_ENSURE_SUCCESS(rv, rv);
2650 rv = xpcom.SetWindowCreator(aNative);
2651 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
2653 { // extra scoping is needed so we release these components before xpcom
2654 // shutdown
2655 nsCOMPtr<nsIStringBundleService> sbs =
2656 mozilla::components::StringBundle::Service();
2657 NS_ENSURE_TRUE(sbs, NS_ERROR_FAILURE);
2659 nsCOMPtr<nsIStringBundle> sb;
2660 sbs->CreateBundle(kProfileProperties, getter_AddRefs(sb));
2661 NS_ENSURE_TRUE_LOG(sbs, NS_ERROR_FAILURE);
2663 NS_ConvertUTF8toUTF16 appName(gAppData->name);
2664 AutoTArray<nsString, 2> params = {appName, appName};
2666 // profileMissing
2667 nsAutoString missingMessage;
2668 rv = sb->FormatStringFromName("profileMissing", params, missingMessage);
2669 NS_ENSURE_SUCCESS(rv, NS_ERROR_ABORT);
2671 nsAutoString missingTitle;
2672 params.SetLength(1);
2673 rv = sb->FormatStringFromName("profileMissingTitle", params, missingTitle);
2674 NS_ENSURE_SUCCESS(rv, NS_ERROR_ABORT);
2676 nsCOMPtr<nsIPromptService> ps(do_GetService(NS_PROMPTSERVICE_CONTRACTID));
2677 NS_ENSURE_TRUE(ps, NS_ERROR_FAILURE);
2679 ps->Alert(nullptr, missingTitle.get(), missingMessage.get());
2681 return NS_ERROR_ABORT;
2683 #endif // MOZ_WIDGET_ANDROID
2686 static ReturnAbortOnError ProfileLockedDialog(nsIFile* aProfileDir,
2687 nsIFile* aProfileLocalDir,
2688 nsIProfileUnlocker* aUnlocker,
2689 nsINativeAppSupport* aNative,
2690 nsIProfileLock** aResult) {
2691 nsresult rv;
2693 bool exists;
2694 aProfileDir->Exists(&exists);
2695 if (!exists) {
2696 return ProfileMissingDialog(aNative);
2699 ScopedXPCOMStartup xpcom;
2700 rv = xpcom.Initialize();
2701 NS_ENSURE_SUCCESS(rv, rv);
2703 #if defined(MOZ_TELEMETRY_REPORTING)
2704 // We cannot check if telemetry has been disabled by the user, yet.
2705 // So, rely on the build time settings, instead.
2706 mozilla::Telemetry::WriteFailedProfileLock(aProfileDir);
2707 #endif
2709 rv = xpcom.SetWindowCreator(aNative);
2710 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
2712 { // extra scoping is needed so we release these components before xpcom
2713 // shutdown
2714 nsCOMPtr<nsIStringBundleService> sbs =
2715 mozilla::components::StringBundle::Service();
2716 NS_ENSURE_TRUE(sbs, NS_ERROR_FAILURE);
2718 nsCOMPtr<nsIStringBundle> sb;
2719 sbs->CreateBundle(kProfileProperties, getter_AddRefs(sb));
2720 NS_ENSURE_TRUE_LOG(sbs, NS_ERROR_FAILURE);
2722 NS_ConvertUTF8toUTF16 appName(gAppData->name);
2723 AutoTArray<nsString, 3> params = {appName, appName, appName};
2725 nsAutoString killMessage;
2726 #ifndef XP_MACOSX
2727 rv = sb->FormatStringFromName(
2728 aUnlocker ? "restartMessageUnlocker" : "restartMessageNoUnlocker2",
2729 params, killMessage);
2730 #else
2731 rv = sb->FormatStringFromName(
2732 aUnlocker ? "restartMessageUnlockerMac" : "restartMessageNoUnlockerMac",
2733 params, killMessage);
2734 #endif
2735 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
2737 params.SetLength(1);
2738 nsAutoString killTitle;
2739 rv = sb->FormatStringFromName("restartTitle", params, killTitle);
2740 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
2742 #ifdef MOZ_BACKGROUNDTASKS
2743 if (BackgroundTasks::IsBackgroundTaskMode()) {
2744 // This error is handled specially to exit with a non-zero exit code.
2745 printf_stderr("%s\n", NS_LossyConvertUTF16toASCII(killMessage).get());
2746 return NS_ERROR_UNEXPECTED;
2748 #endif
2750 if (gfxPlatform::IsHeadless()) {
2751 // TODO: make a way to turn off all dialogs when headless.
2752 Output(true, "%s\n", NS_LossyConvertUTF16toASCII(killMessage).get());
2753 return NS_ERROR_FAILURE;
2756 nsCOMPtr<nsIPromptService> ps(do_GetService(NS_PROMPTSERVICE_CONTRACTID));
2757 NS_ENSURE_TRUE(ps, NS_ERROR_FAILURE);
2759 if (aUnlocker) {
2760 int32_t button;
2761 #ifdef MOZ_WIDGET_ANDROID
2762 // On Android we always kill the process if the lock is still being held
2763 button = 0;
2764 #else
2765 const uint32_t flags = (nsIPromptService::BUTTON_TITLE_IS_STRING *
2766 nsIPromptService::BUTTON_POS_0) +
2767 (nsIPromptService::BUTTON_TITLE_CANCEL *
2768 nsIPromptService::BUTTON_POS_1);
2770 bool checkState = false;
2771 rv = ps->ConfirmEx(nullptr, killTitle.get(), killMessage.get(), flags,
2772 killTitle.get(), nullptr, nullptr, nullptr,
2773 &checkState, &button);
2774 NS_ENSURE_SUCCESS_LOG(rv, rv);
2775 #endif
2777 if (button == 0) {
2778 rv = aUnlocker->Unlock(nsIProfileUnlocker::FORCE_QUIT);
2779 if (NS_FAILED(rv)) {
2780 return rv;
2783 SaveFileToEnv("XRE_PROFILE_PATH", aProfileDir);
2784 SaveFileToEnv("XRE_PROFILE_LOCAL_PATH", aProfileLocalDir);
2786 #if defined(MOZ_HAS_REMOTE)
2787 if (gRemoteService) {
2788 gRemoteService->UnlockStartup();
2789 gRemoteService = nullptr;
2791 #endif
2792 return LaunchChild(false, true);
2794 } else {
2795 rv = ps->Alert(nullptr, killTitle.get(), killMessage.get());
2796 NS_ENSURE_SUCCESS_LOG(rv, rv);
2799 return NS_ERROR_ABORT;
2803 static const char kProfileManagerURL[] =
2804 "chrome://mozapps/content/profile/profileSelection.xhtml";
2806 static ReturnAbortOnError ShowProfileManager(
2807 nsIToolkitProfileService* aProfileSvc, nsINativeAppSupport* aNative) {
2808 nsresult rv;
2810 nsCOMPtr<nsIFile> profD, profLD;
2811 bool offline = false;
2812 int32_t dialogReturn;
2815 ScopedXPCOMStartup xpcom;
2816 rv = xpcom.Initialize();
2817 NS_ENSURE_SUCCESS(rv, rv);
2819 rv = xpcom.SetWindowCreator(aNative);
2820 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
2822 #ifdef XP_MACOSX
2823 InitializeMacApp();
2824 CommandLineServiceMac::SetupMacCommandLine(gRestartArgc, gRestartArgv,
2825 true);
2826 #endif
2828 { // extra scoping is needed so we release these components before xpcom
2829 // shutdown
2830 nsCOMPtr<nsIWindowWatcher> windowWatcher(
2831 do_GetService(NS_WINDOWWATCHER_CONTRACTID));
2832 nsCOMPtr<nsIDialogParamBlock> ioParamBlock(
2833 do_CreateInstance(NS_DIALOGPARAMBLOCK_CONTRACTID));
2834 nsCOMPtr<nsIMutableArray> dlgArray(
2835 do_CreateInstance(NS_ARRAY_CONTRACTID));
2836 NS_ENSURE_TRUE(windowWatcher && ioParamBlock && dlgArray,
2837 NS_ERROR_FAILURE);
2839 ioParamBlock->SetObjects(dlgArray);
2841 nsCOMPtr<nsIAppStartup> appStartup(components::AppStartup::Service());
2842 NS_ENSURE_TRUE(appStartup, NS_ERROR_FAILURE);
2844 nsAutoCString features("centerscreen,chrome,modal,titlebar");
2845 // If we're launching a private browsing window make sure to set that
2846 // feature for the Profile Manager window as well, so it groups correctly
2847 // on the Windows taskbar.
2848 if (CheckArgExists("private-window") == ARG_FOUND) {
2849 features.AppendLiteral(",private");
2851 nsCOMPtr<mozIDOMWindowProxy> newWindow;
2852 rv = windowWatcher->OpenWindow(
2853 nullptr, nsDependentCString(kProfileManagerURL), "_blank"_ns,
2854 features, ioParamBlock, getter_AddRefs(newWindow));
2856 NS_ENSURE_SUCCESS_LOG(rv, rv);
2858 rv = ioParamBlock->GetInt(0, &dialogReturn);
2859 if (NS_FAILED(rv) || dialogReturn == nsIToolkitProfileService::exit) {
2860 return NS_ERROR_ABORT;
2863 int32_t startOffline;
2864 rv = ioParamBlock->GetInt(1, &startOffline);
2865 offline = NS_SUCCEEDED(rv) && startOffline == 1;
2867 rv = dlgArray->QueryElementAt(0, NS_GET_IID(nsIFile),
2868 getter_AddRefs(profD));
2869 NS_ENSURE_SUCCESS_LOG(rv, rv);
2871 rv = dlgArray->QueryElementAt(1, NS_GET_IID(nsIFile),
2872 getter_AddRefs(profLD));
2873 NS_ENSURE_SUCCESS_LOG(rv, rv);
2877 if (offline) {
2878 SaveToEnv("XRE_START_OFFLINE=1");
2881 // User requested that we restart back into the profile manager.
2882 if (dialogReturn == nsIToolkitProfileService::restart) {
2883 SaveToEnv("XRE_RESTART_TO_PROFILE_MANAGER=1");
2884 SaveToEnv("XRE_RESTARTED_BY_PROFILE_MANAGER=1");
2885 } else {
2886 MOZ_ASSERT(dialogReturn == nsIToolkitProfileService::launchWithProfile);
2887 SaveFileToEnv("XRE_PROFILE_PATH", profD);
2888 SaveFileToEnv("XRE_PROFILE_LOCAL_PATH", profLD);
2889 SaveToEnv("XRE_RESTARTED_BY_PROFILE_MANAGER=1");
2892 if (gRestartedByOS) {
2893 // Re-add this argument when actually starting the application.
2894 char** newArgv =
2895 (char**)realloc(gRestartArgv, sizeof(char*) * (gRestartArgc + 2));
2896 NS_ENSURE_TRUE(newArgv, NS_ERROR_OUT_OF_MEMORY);
2897 gRestartArgv = newArgv;
2898 gRestartArgv[gRestartArgc++] = const_cast<char*>("-os-restarted");
2899 gRestartArgv[gRestartArgc] = nullptr;
2901 #if defined(MOZ_HAS_REMOTE)
2902 if (gRemoteService) {
2903 gRemoteService->UnlockStartup();
2904 gRemoteService = nullptr;
2906 #endif
2907 return LaunchChild(false, true);
2910 static bool gDoMigration = false;
2911 static bool gDoProfileReset = false;
2912 static nsCOMPtr<nsIToolkitProfile> gResetOldProfile;
2914 static nsresult LockProfile(nsINativeAppSupport* aNative, nsIFile* aRootDir,
2915 nsIFile* aLocalDir, nsIToolkitProfile* aProfile,
2916 nsIProfileLock** aResult) {
2917 // If you close Firefox and very quickly reopen it, the old Firefox may
2918 // still be closing down. Rather than immediately showing the
2919 // "Firefox is running but is not responding" message, we spend a few
2920 // seconds retrying first.
2922 static const int kLockRetrySeconds = 5;
2923 static const int kLockRetrySleepMS = 100;
2925 nsresult rv;
2926 nsCOMPtr<nsIProfileUnlocker> unlocker;
2927 const TimeStamp start = TimeStamp::Now();
2928 do {
2929 if (aProfile) {
2930 rv = aProfile->Lock(getter_AddRefs(unlocker), aResult);
2931 } else {
2932 rv = NS_LockProfilePath(aRootDir, aLocalDir, getter_AddRefs(unlocker),
2933 aResult);
2935 if (NS_SUCCEEDED(rv)) {
2936 StartupTimeline::Record(StartupTimeline::AFTER_PROFILE_LOCKED);
2937 return NS_OK;
2939 PR_Sleep(kLockRetrySleepMS);
2940 } while (TimeStamp::Now() - start <
2941 TimeDuration::FromSeconds(kLockRetrySeconds));
2943 return ProfileLockedDialog(aRootDir, aLocalDir, unlocker, aNative, aResult);
2946 // Pick a profile. We need to end up with a profile root dir, local dir and
2947 // potentially an nsIToolkitProfile instance.
2949 // 1) check for --profile <path>
2950 // 2) check for -P <name>
2951 // 3) check for --ProfileManager
2952 // 4) use the default profile, if there is one
2953 // 5) if there are *no* profiles, set up profile-migration
2954 // 6) display the profile-manager UI
2955 static nsresult SelectProfile(nsToolkitProfileService* aProfileSvc,
2956 nsINativeAppSupport* aNative, nsIFile** aRootDir,
2957 nsIFile** aLocalDir, nsIToolkitProfile** aProfile,
2958 bool* aWasDefaultSelection) {
2959 StartupTimeline::Record(StartupTimeline::SELECT_PROFILE);
2961 nsresult rv;
2963 if (EnvHasValue("MOZ_RESET_PROFILE_RESTART")) {
2964 gDoProfileReset = true;
2965 gDoMigration = true;
2968 // reset-profile and migration args need to be checked before any profiles are
2969 // chosen below.
2970 ArgResult ar = CheckArg("reset-profile");
2971 if (ar == ARG_FOUND) {
2972 gDoProfileReset = true;
2975 ar = CheckArg("migration");
2976 if (ar == ARG_FOUND) {
2977 gDoMigration = true;
2980 #if defined(XP_WIN)
2981 // This arg is only used to indicate to telemetry that a profile refresh
2982 // (reset+migration) was requested from the uninstaller, pass this along
2983 // via an environment variable for simplicity.
2984 ar = CheckArg("uninstaller-profile-refresh");
2985 if (ar == ARG_FOUND) {
2986 SaveToEnv("MOZ_UNINSTALLER_PROFILE_REFRESH=1");
2988 #endif
2990 if (EnvHasValue("XRE_RESTART_TO_PROFILE_MANAGER")) {
2991 return ShowProfileManager(aProfileSvc, aNative);
2994 // Ask the profile manager to select the profile directories to use.
2995 bool didCreate = false;
2996 rv = aProfileSvc->SelectStartupProfile(&gArgc, gArgv, gDoProfileReset,
2997 aRootDir, aLocalDir, aProfile,
2998 &didCreate, aWasDefaultSelection);
3000 if (rv == NS_ERROR_SHOW_PROFILE_MANAGER) {
3001 return ShowProfileManager(aProfileSvc, aNative);
3004 NS_ENSURE_SUCCESS(rv, rv);
3006 if (didCreate) {
3007 // For a fresh install, we would like to let users decide
3008 // to do profile migration on their own later after using.
3009 gDoProfileReset = false;
3010 gDoMigration = false;
3013 if (gDoProfileReset && !*aProfile) {
3014 NS_WARNING("Profile reset is only supported for named profiles.");
3015 return NS_ERROR_ABORT;
3018 // No profile could be found. This generally shouldn't happen, a new profile
3019 // should be created in all cases except for profile reset which is covered
3020 // above, but just in case...
3021 if (!*aRootDir) {
3022 NS_WARNING("Failed to select or create profile.");
3023 return NS_ERROR_ABORT;
3026 return NS_OK;
3029 #ifdef MOZ_BLOCK_PROFILE_DOWNGRADE
3030 struct FileWriteFunc final : public JSONWriteFunc {
3031 FILE* mFile;
3032 explicit FileWriteFunc(FILE* aFile) : mFile(aFile) {}
3034 void Write(const Span<const char>& aStr) final {
3035 fprintf(mFile, "%.*s", int(aStr.size()), aStr.data());
3039 static void SubmitDowngradeTelemetry(const nsCString& aLastVersion,
3040 bool aHasSync, int32_t aButton) {
3041 nsCOMPtr<nsIPrefService> prefSvc =
3042 do_GetService("@mozilla.org/preferences-service;1");
3043 NS_ENSURE_TRUE_VOID(prefSvc);
3045 nsCOMPtr<nsIPrefBranch> prefBranch = do_QueryInterface(prefSvc);
3046 NS_ENSURE_TRUE_VOID(prefBranch);
3048 bool enabled;
3049 nsresult rv =
3050 prefBranch->GetBoolPref(kPrefHealthReportUploadEnabled, &enabled);
3051 NS_ENSURE_SUCCESS_VOID(rv);
3052 if (!enabled) {
3053 return;
3056 nsCString server;
3057 rv = prefBranch->GetCharPref("toolkit.telemetry.server", server);
3058 NS_ENSURE_SUCCESS_VOID(rv);
3060 nsCString clientId;
3061 rv = prefBranch->GetCharPref("toolkit.telemetry.cachedClientID", clientId);
3062 NS_ENSURE_SUCCESS_VOID(rv);
3064 rv = prefSvc->GetDefaultBranch(nullptr, getter_AddRefs(prefBranch));
3065 NS_ENSURE_SUCCESS_VOID(rv);
3067 nsCString channel("default");
3068 rv = prefBranch->GetCharPref("app.update.channel", channel);
3069 NS_ENSURE_SUCCESS_VOID(rv);
3071 nsID uuid;
3072 rv = nsID::GenerateUUIDInPlace(uuid);
3073 NS_ENSURE_SUCCESS_VOID(rv);
3075 nsCString arch("null");
3076 nsCOMPtr<nsIPropertyBag2> sysInfo =
3077 do_GetService("@mozilla.org/system-info;1");
3078 NS_ENSURE_TRUE_VOID(sysInfo);
3079 sysInfo->GetPropertyAsACString(u"arch"_ns, arch);
3081 time_t now;
3082 time(&now);
3083 char date[sizeof "YYYY-MM-DDThh:mm:ss.000Z"];
3084 strftime(date, sizeof date, "%FT%T.000Z", gmtime(&now));
3086 NSID_TrimBracketsASCII pingId(uuid);
3087 constexpr auto pingType = "downgrade"_ns;
3089 int32_t pos = aLastVersion.Find("_");
3090 if (pos == kNotFound) {
3091 return;
3094 const nsDependentCSubstring lastVersion = Substring(aLastVersion, 0, pos);
3095 const nsDependentCSubstring lastBuildId =
3096 Substring(aLastVersion, pos + 1, 14);
3098 nsPrintfCString url("%s/submit/telemetry/%s/%s/%s/%s/%s/%s?v=%d",
3099 server.get(), PromiseFlatCString(pingId).get(),
3100 pingType.get(), (const char*)gAppData->name,
3101 (const char*)gAppData->version, channel.get(),
3102 (const char*)gAppData->buildID,
3103 TELEMETRY_PING_FORMAT_VERSION);
3105 nsCOMPtr<nsIFile> pingFile;
3106 rv = NS_GetSpecialDirectory(XRE_USER_APP_DATA_DIR, getter_AddRefs(pingFile));
3107 NS_ENSURE_SUCCESS_VOID(rv);
3108 rv = pingFile->Append(u"Pending Pings"_ns);
3109 NS_ENSURE_SUCCESS_VOID(rv);
3110 rv = pingFile->Create(nsIFile::DIRECTORY_TYPE, 0755);
3111 if (NS_FAILED(rv) && rv != NS_ERROR_FILE_ALREADY_EXISTS) {
3112 return;
3114 rv = pingFile->Append(NS_ConvertUTF8toUTF16(pingId));
3115 NS_ENSURE_SUCCESS_VOID(rv);
3117 nsCOMPtr<nsIFile> pingSender;
3118 rv = NS_GetSpecialDirectory(NS_GRE_BIN_DIR, getter_AddRefs(pingSender));
3119 NS_ENSURE_SUCCESS_VOID(rv);
3120 # ifdef XP_WIN
3121 pingSender->Append(u"pingsender.exe"_ns);
3122 # else
3123 pingSender->Append(u"pingsender"_ns);
3124 # endif
3126 bool exists;
3127 rv = pingSender->Exists(&exists);
3128 NS_ENSURE_SUCCESS_VOID(rv);
3129 if (!exists) {
3130 return;
3133 FILE* file;
3134 rv = pingFile->OpenANSIFileDesc("w", &file);
3135 NS_ENSURE_SUCCESS_VOID(rv);
3137 JSONWriter w(MakeUnique<FileWriteFunc>(file));
3138 w.Start();
3140 w.StringProperty("type",
3141 Span<const char>(pingType.Data(), pingType.Length()));
3142 w.StringProperty("id", PromiseFlatCString(pingId));
3143 w.StringProperty("creationDate", MakeStringSpan(date));
3144 w.IntProperty("version", TELEMETRY_PING_FORMAT_VERSION);
3145 w.StringProperty("clientId", clientId);
3146 w.StartObjectProperty("application");
3148 w.StringProperty("architecture", arch);
3149 w.StringProperty(
3150 "buildId",
3151 MakeStringSpan(static_cast<const char*>(gAppData->buildID)));
3152 w.StringProperty(
3153 "name", MakeStringSpan(static_cast<const char*>(gAppData->name)));
3154 w.StringProperty(
3155 "version",
3156 MakeStringSpan(static_cast<const char*>(gAppData->version)));
3157 w.StringProperty("displayVersion",
3158 MOZ_STRINGIFY(MOZ_APP_VERSION_DISPLAY));
3159 w.StringProperty(
3160 "vendor", MakeStringSpan(static_cast<const char*>(gAppData->vendor)));
3161 w.StringProperty("platformVersion", gToolkitVersion);
3162 # ifdef TARGET_XPCOM_ABI
3163 w.StringProperty("xpcomAbi", TARGET_XPCOM_ABI);
3164 # else
3165 w.StringProperty("xpcomAbi", "unknown");
3166 # endif
3167 w.StringProperty("channel", channel);
3169 w.EndObject();
3170 w.StartObjectProperty("payload");
3172 w.StringProperty("lastVersion", PromiseFlatCString(lastVersion));
3173 w.StringProperty("lastBuildId", PromiseFlatCString(lastBuildId));
3174 w.BoolProperty("hasSync", aHasSync);
3175 w.IntProperty("button", aButton);
3177 w.EndObject();
3179 w.End();
3181 fclose(file);
3183 PathString filePath = pingFile->NativePath();
3184 const filesystem::Path::value_type* args[2];
3185 # ifdef XP_WIN
3186 nsString urlw = NS_ConvertUTF8toUTF16(url);
3187 args[0] = urlw.get();
3188 # else
3189 args[0] = url.get();
3190 # endif
3191 args[1] = filePath.get();
3193 nsCOMPtr<nsIProcess> process =
3194 do_CreateInstance("@mozilla.org/process/util;1");
3195 NS_ENSURE_TRUE_VOID(process);
3196 process->Init(pingSender);
3197 process->SetStartHidden(true);
3198 process->SetNoShell(true);
3200 # ifdef XP_WIN
3201 process->Runw(false, args, 2);
3202 # else
3203 process->Run(false, args, 2);
3204 # endif
3207 static const char kProfileDowngradeURL[] =
3208 "chrome://mozapps/content/profile/profileDowngrade.xhtml";
3210 static ReturnAbortOnError CheckDowngrade(nsIFile* aProfileDir,
3211 nsINativeAppSupport* aNative,
3212 nsIToolkitProfileService* aProfileSvc,
3213 const nsCString& aLastVersion) {
3214 int32_t result = 0;
3215 nsresult rv;
3218 if (gfxPlatform::IsHeadless()) {
3219 // TODO: make a way to turn off all dialogs when headless.
3220 Output(true,
3221 "This profile was last used with a newer version of this "
3222 "application. Please create a new profile.\n");
3223 return NS_ERROR_ABORT;
3226 ScopedXPCOMStartup xpcom;
3227 rv = xpcom.Initialize();
3228 NS_ENSURE_SUCCESS(rv, rv);
3230 rv = xpcom.SetWindowCreator(aNative);
3231 NS_ENSURE_SUCCESS(rv, rv);
3233 { // extra scoping is needed so we release these components before xpcom
3234 // shutdown
3235 bool hasSync = false;
3236 nsCOMPtr<nsIPrefService> prefSvc =
3237 do_GetService("@mozilla.org/preferences-service;1");
3238 NS_ENSURE_TRUE(prefSvc, rv);
3240 nsCOMPtr<nsIFile> prefsFile;
3241 rv = aProfileDir->Clone(getter_AddRefs(prefsFile));
3242 NS_ENSURE_SUCCESS(rv, rv);
3244 rv = prefsFile->Append(u"prefs.js"_ns);
3245 NS_ENSURE_SUCCESS(rv, rv);
3247 rv = prefSvc->ReadUserPrefsFromFile(prefsFile);
3248 if (NS_SUCCEEDED(rv)) {
3249 nsCOMPtr<nsIPrefBranch> prefBranch = do_QueryInterface(prefSvc);
3251 rv = prefBranch->PrefHasUserValue("services.sync.username", &hasSync);
3252 NS_ENSURE_SUCCESS(rv, rv);
3255 nsCOMPtr<nsIWindowWatcher> windowWatcher =
3256 do_GetService(NS_WINDOWWATCHER_CONTRACTID);
3257 NS_ENSURE_TRUE(windowWatcher, NS_ERROR_ABORT);
3259 nsCOMPtr<nsIAppStartup> appStartup(components::AppStartup::Service());
3260 NS_ENSURE_TRUE(appStartup, NS_ERROR_FAILURE);
3262 nsCOMPtr<nsIDialogParamBlock> paramBlock =
3263 do_CreateInstance(NS_DIALOGPARAMBLOCK_CONTRACTID);
3264 NS_ENSURE_TRUE(paramBlock, NS_ERROR_ABORT);
3266 uint8_t flags = 0;
3267 if (hasSync) {
3268 flags |= nsIToolkitProfileService::hasSync;
3271 paramBlock->SetInt(0, flags);
3273 nsAutoCString features("centerscreen,chrome,modal,titlebar");
3274 // If we're launching a private browsing window make sure to set that
3275 // feature for the Profile Manager window as well, so it groups correctly
3276 // on the Windows taskbar.
3277 if (CheckArgExists("private-window") == ARG_FOUND) {
3278 features.AppendLiteral(",private");
3280 nsCOMPtr<mozIDOMWindowProxy> newWindow;
3281 rv = windowWatcher->OpenWindow(
3282 nullptr, nsDependentCString(kProfileDowngradeURL), "_blank"_ns,
3283 features, paramBlock, getter_AddRefs(newWindow));
3284 NS_ENSURE_SUCCESS(rv, rv);
3286 paramBlock->GetInt(1, &result);
3288 SubmitDowngradeTelemetry(aLastVersion, hasSync, result);
3292 if (result == nsIToolkitProfileService::createNewProfile) {
3293 // Create a new profile and start it.
3294 nsCString profileName;
3295 profileName.AssignLiteral("default");
3296 # ifdef MOZ_DEDICATED_PROFILES
3297 profileName.Append("-" MOZ_STRINGIFY(MOZ_UPDATE_CHANNEL));
3298 # endif
3299 nsCOMPtr<nsIToolkitProfile> newProfile;
3300 rv = aProfileSvc->CreateUniqueProfile(nullptr, profileName,
3301 getter_AddRefs(newProfile));
3302 NS_ENSURE_SUCCESS(rv, rv);
3303 rv = aProfileSvc->SetDefaultProfile(newProfile);
3304 NS_ENSURE_SUCCESS(rv, rv);
3305 rv = aProfileSvc->Flush();
3306 NS_ENSURE_SUCCESS(rv, rv);
3308 nsCOMPtr<nsIFile> profD, profLD;
3309 rv = newProfile->GetRootDir(getter_AddRefs(profD));
3310 NS_ENSURE_SUCCESS(rv, rv);
3311 rv = newProfile->GetLocalDir(getter_AddRefs(profLD));
3312 NS_ENSURE_SUCCESS(rv, rv);
3314 SaveFileToEnv("XRE_PROFILE_PATH", profD);
3315 SaveFileToEnv("XRE_PROFILE_LOCAL_PATH", profLD);
3317 return LaunchChild(false, true);
3320 // Cancel
3321 return NS_ERROR_ABORT;
3323 #endif
3326 * Extracts the various parts of a compatibility version string.
3328 * Compatibility versions are of the form
3329 * "<appversion>_<appbuildid>/<platformbuildid>". The toolkit version comparator
3330 * can only handle 32-bit numbers and in the normal case build IDs are larger
3331 * than this. So if the build ID is numeric we split it into two version parts.
3333 static void ExtractCompatVersionInfo(const nsACString& aCompatVersion,
3334 nsACString& aAppVersion,
3335 nsACString& aAppBuildID) {
3336 int32_t underscorePos = aCompatVersion.FindChar('_');
3337 int32_t slashPos = aCompatVersion.FindChar('/');
3339 if (underscorePos == kNotFound || slashPos == kNotFound ||
3340 slashPos < underscorePos) {
3341 NS_WARNING(
3342 "compatibility.ini Version string does not match the expected format.");
3344 // Fall back to just using the entire string as the version.
3345 aAppVersion = aCompatVersion;
3346 aAppBuildID.Truncate(0);
3347 return;
3350 aAppVersion = Substring(aCompatVersion, 0, underscorePos);
3351 aAppBuildID = Substring(aCompatVersion, underscorePos + 1,
3352 slashPos - (underscorePos + 1));
3356 * Compares the provided compatibility versions. Returns 0 if they match,
3357 * < 0 if the new version is considered an upgrade from the old version and
3358 * > 0 if the new version is considered a downgrade from the old version.
3360 int32_t CompareCompatVersions(const nsACString& aOldCompatVersion,
3361 const nsACString& aNewCompatVersion) {
3362 // Hardcode the case where the last run was in safe mode (Bug 1556612). We
3363 // cannot tell if this is a downgrade or not so just assume it isn't and let
3364 // the user proceed.
3365 if (aOldCompatVersion.EqualsLiteral("Safe Mode")) {
3366 return -1;
3369 // Extract the major version part from the version string and only use that
3370 // for version comparison.
3371 int32_t index = aOldCompatVersion.FindChar('.');
3372 const nsACString& oldMajorVersion = Substring(
3373 aOldCompatVersion, 0, index < 0 ? aOldCompatVersion.Length() : index);
3374 index = aNewCompatVersion.FindChar('.');
3375 const nsACString& newMajorVersion = Substring(
3376 aNewCompatVersion, 0, index < 0 ? aNewCompatVersion.Length() : index);
3378 return CompareVersions(PromiseFlatCString(oldMajorVersion).get(),
3379 PromiseFlatCString(newMajorVersion).get());
3383 * Checks the compatibility.ini file to see if we have updated our application
3384 * or otherwise invalidated our caches. If the application has been updated,
3385 * we return false; otherwise, we return true.
3387 * We also write the status of the caches (valid/invalid) into the return param
3388 * aCachesOK. The aCachesOK is always invalid if the application has been
3389 * updated.
3391 * Finally, aIsDowngrade is set to true if the current application is older
3392 * than that previously used by the profile.
3394 static bool CheckCompatibility(nsIFile* aProfileDir, const nsCString& aVersion,
3395 const nsCString& aOSABI, nsIFile* aXULRunnerDir,
3396 nsIFile* aAppDir, nsIFile* aFlagFile,
3397 bool* aCachesOK, bool* aIsDowngrade,
3398 nsCString& aLastVersion) {
3399 *aCachesOK = false;
3400 *aIsDowngrade = false;
3401 gLastAppVersion.SetIsVoid(true);
3402 gLastAppBuildID.SetIsVoid(true);
3404 nsCOMPtr<nsIFile> file;
3405 aProfileDir->Clone(getter_AddRefs(file));
3406 if (!file) return false;
3407 file->AppendNative(FILE_COMPATIBILITY_INFO);
3409 nsINIParser parser;
3410 nsresult rv = parser.Init(file);
3411 if (NS_FAILED(rv)) return false;
3413 rv = parser.GetString("Compatibility", "LastVersion", aLastVersion);
3414 if (NS_FAILED(rv)) {
3415 return false;
3418 if (!aLastVersion.Equals(aVersion)) {
3419 // The version is not the same. Whether it's a downgrade depends on an
3420 // actual comparison:
3421 *aIsDowngrade = 0 < CompareCompatVersions(aLastVersion, aVersion);
3422 ExtractCompatVersionInfo(aLastVersion, gLastAppVersion, gLastAppBuildID);
3423 return false;
3426 // If we get here, the version matched, but there may still be other
3427 // differences between us and the build that the profile last ran under.
3429 gLastAppVersion.Assign(gAppData->version);
3430 gLastAppBuildID.Assign(gAppData->buildID);
3432 nsAutoCString buf;
3433 rv = parser.GetString("Compatibility", "LastOSABI", buf);
3434 if (NS_FAILED(rv) || !aOSABI.Equals(buf)) return false;
3436 rv = parser.GetString("Compatibility", "LastPlatformDir", buf);
3437 if (NS_FAILED(rv)) return false;
3439 nsCOMPtr<nsIFile> lf;
3440 rv = NS_NewNativeLocalFile(""_ns, false, getter_AddRefs(lf));
3441 if (NS_FAILED(rv)) return false;
3443 rv = lf->SetPersistentDescriptor(buf);
3444 if (NS_FAILED(rv)) return false;
3446 bool eq;
3447 rv = lf->Equals(aXULRunnerDir, &eq);
3448 if (NS_FAILED(rv) || !eq) return false;
3450 if (aAppDir) {
3451 rv = parser.GetString("Compatibility", "LastAppDir", buf);
3452 if (NS_FAILED(rv)) return false;
3454 rv = NS_NewNativeLocalFile(""_ns, false, getter_AddRefs(lf));
3455 if (NS_FAILED(rv)) return false;
3457 rv = lf->SetPersistentDescriptor(buf);
3458 if (NS_FAILED(rv)) return false;
3460 rv = lf->Equals(aAppDir, &eq);
3461 if (NS_FAILED(rv) || !eq) return false;
3464 // If we see this flag, caches are invalid.
3465 rv = parser.GetString("Compatibility", "InvalidateCaches", buf);
3466 *aCachesOK = (NS_FAILED(rv) || !buf.EqualsLiteral("1"));
3468 bool purgeCaches = false;
3469 if (aFlagFile && NS_SUCCEEDED(aFlagFile->Exists(&purgeCaches)) &&
3470 purgeCaches) {
3471 *aCachesOK = false;
3474 return true;
3477 void BuildCompatVersion(const char* aAppVersion, const char* aAppBuildID,
3478 const char* aToolkitBuildID, nsACString& aBuf) {
3479 aBuf.Assign(aAppVersion);
3480 aBuf.Append('_');
3481 aBuf.Append(aAppBuildID);
3482 aBuf.Append('/');
3483 aBuf.Append(aToolkitBuildID);
3486 static void BuildVersion(nsCString& aBuf) {
3487 BuildCompatVersion(gAppData->version, gAppData->buildID, gToolkitBuildID,
3488 aBuf);
3491 static void WriteVersion(nsIFile* aProfileDir, const nsCString& aVersion,
3492 const nsCString& aOSABI, nsIFile* aXULRunnerDir,
3493 nsIFile* aAppDir, bool invalidateCache) {
3494 nsCOMPtr<nsIFile> file;
3495 aProfileDir->Clone(getter_AddRefs(file));
3496 if (!file) return;
3497 file->AppendNative(FILE_COMPATIBILITY_INFO);
3499 nsAutoCString platformDir;
3500 Unused << aXULRunnerDir->GetPersistentDescriptor(platformDir);
3502 nsAutoCString appDir;
3503 if (aAppDir) Unused << aAppDir->GetPersistentDescriptor(appDir);
3505 PRFileDesc* fd;
3506 nsresult rv = file->OpenNSPRFileDesc(PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE,
3507 0600, &fd);
3508 if (NS_FAILED(rv)) {
3509 NS_ERROR("could not create output stream");
3510 return;
3513 static const char kHeader[] = "[Compatibility]" NS_LINEBREAK "LastVersion=";
3515 PR_Write(fd, kHeader, sizeof(kHeader) - 1);
3516 PR_Write(fd, aVersion.get(), aVersion.Length());
3518 static const char kOSABIHeader[] = NS_LINEBREAK "LastOSABI=";
3519 PR_Write(fd, kOSABIHeader, sizeof(kOSABIHeader) - 1);
3520 PR_Write(fd, aOSABI.get(), aOSABI.Length());
3522 static const char kPlatformDirHeader[] = NS_LINEBREAK "LastPlatformDir=";
3524 PR_Write(fd, kPlatformDirHeader, sizeof(kPlatformDirHeader) - 1);
3525 PR_Write(fd, platformDir.get(), platformDir.Length());
3527 static const char kAppDirHeader[] = NS_LINEBREAK "LastAppDir=";
3528 if (aAppDir) {
3529 PR_Write(fd, kAppDirHeader, sizeof(kAppDirHeader) - 1);
3530 PR_Write(fd, appDir.get(), appDir.Length());
3533 static const char kInvalidationHeader[] = NS_LINEBREAK "InvalidateCaches=1";
3534 if (invalidateCache)
3535 PR_Write(fd, kInvalidationHeader, sizeof(kInvalidationHeader) - 1);
3537 static const char kNL[] = NS_LINEBREAK;
3538 PR_Write(fd, kNL, sizeof(kNL) - 1);
3540 PR_Close(fd);
3544 * Returns true if the startup cache file was successfully removed.
3545 * Returns false if file->Clone fails at any point (OOM) or if unable
3546 * to remove the startup cache file. Note in particular the return value
3547 * is unaffected by a failure to remove extensions.ini
3549 static bool RemoveComponentRegistries(nsIFile* aProfileDir,
3550 nsIFile* aLocalProfileDir,
3551 bool aRemoveEMFiles) {
3552 nsCOMPtr<nsIFile> file;
3553 aProfileDir->Clone(getter_AddRefs(file));
3554 if (!file) return false;
3556 if (aRemoveEMFiles) {
3557 file->SetNativeLeafName("extensions.ini"_ns);
3558 file->Remove(false);
3561 aLocalProfileDir->Clone(getter_AddRefs(file));
3562 if (!file) return false;
3564 file->AppendNative("startupCache"_ns);
3565 nsresult rv = file->Remove(true);
3566 return NS_SUCCEEDED(rv) || rv == NS_ERROR_FILE_NOT_FOUND;
3569 // When we first initialize the crash reporter we don't have a profile,
3570 // so we set the minidump path to $TEMP. Once we have a profile,
3571 // we set it to $PROFILE/minidumps, creating the directory
3572 // if needed.
3573 static void MakeOrSetMinidumpPath(nsIFile* profD) {
3574 nsCOMPtr<nsIFile> dumpD;
3575 profD->Clone(getter_AddRefs(dumpD));
3577 if (dumpD) {
3578 bool fileExists;
3579 // XXX: do some more error checking here
3580 dumpD->Append(u"minidumps"_ns);
3581 dumpD->Exists(&fileExists);
3582 if (!fileExists) {
3583 nsresult rv = dumpD->Create(nsIFile::DIRECTORY_TYPE, 0700);
3584 NS_ENSURE_SUCCESS_VOID(rv);
3587 nsAutoString pathStr;
3588 if (NS_SUCCEEDED(dumpD->GetPath(pathStr)))
3589 CrashReporter::SetMinidumpPath(pathStr);
3593 const XREAppData* gAppData = nullptr;
3596 * NSPR will search for the "nspr_use_zone_allocator" symbol throughout
3597 * the process and use it to determine whether the application defines its own
3598 * memory allocator or not.
3600 * Since most applications (e.g. Firefox and Thunderbird) don't use any special
3601 * allocators and therefore don't define this symbol, NSPR must search the
3602 * entire process, which reduces startup performance.
3604 * By defining the symbol here, we can avoid the wasted lookup and hopefully
3605 * improve startup performance.
3607 NS_VISIBILITY_DEFAULT PRBool nspr_use_zone_allocator = PR_FALSE;
3609 #ifdef CAIRO_HAS_DWRITE_FONT
3611 # include <dwrite.h>
3612 # include "nsWindowsHelpers.h"
3614 # ifdef DEBUG_DWRITE_STARTUP
3616 # define LOGREGISTRY(msg) LogRegistryEvent(msg)
3618 // for use when monitoring process
3619 static void LogRegistryEvent(const wchar_t* msg) {
3620 HKEY dummyKey;
3621 HRESULT hr;
3622 wchar_t buf[512];
3624 wsprintf(buf, L" log %s", msg);
3625 hr = RegOpenKeyEx(HKEY_LOCAL_MACHINE, buf, 0, KEY_READ, &dummyKey);
3626 if (SUCCEEDED(hr)) {
3627 RegCloseKey(dummyKey);
3630 # else
3632 # define LOGREGISTRY(msg)
3634 # endif
3636 static DWORD WINAPI InitDwriteBG(LPVOID lpdwThreadParam) {
3637 SetThreadPriority(GetCurrentThread(), THREAD_MODE_BACKGROUND_BEGIN);
3638 LOGREGISTRY(L"loading dwrite.dll");
3639 HMODULE dwdll = LoadLibrarySystem32(L"dwrite.dll");
3640 if (dwdll) {
3641 decltype(DWriteCreateFactory)* createDWriteFactory =
3642 (decltype(DWriteCreateFactory)*)GetProcAddress(dwdll,
3643 "DWriteCreateFactory");
3644 if (createDWriteFactory) {
3645 LOGREGISTRY(L"creating dwrite factory");
3646 IDWriteFactory* factory;
3647 HRESULT hr = createDWriteFactory(DWRITE_FACTORY_TYPE_SHARED,
3648 __uuidof(IDWriteFactory),
3649 reinterpret_cast<IUnknown**>(&factory));
3650 if (SUCCEEDED(hr)) {
3651 LOGREGISTRY(L"dwrite factory done");
3652 factory->Release();
3653 LOGREGISTRY(L"freed factory");
3654 } else {
3655 LOGREGISTRY(L"failed to create factory");
3659 SetThreadPriority(GetCurrentThread(), THREAD_MODE_BACKGROUND_END);
3660 return 0;
3662 #endif
3664 #include "GeckoProfiler.h"
3665 #include "ProfilerControl.h"
3667 // Encapsulates startup and shutdown state for XRE_main
3668 class XREMain {
3669 public:
3670 XREMain() = default;
3672 ~XREMain() {
3673 mScopedXPCOM = nullptr;
3674 mAppData = nullptr;
3677 int XRE_main(int argc, char* argv[], const BootstrapConfig& aConfig);
3678 int XRE_mainInit(bool* aExitFlag);
3679 int XRE_mainStartup(bool* aExitFlag);
3680 nsresult XRE_mainRun();
3682 bool CheckLastStartupWasCrash();
3684 nsCOMPtr<nsINativeAppSupport> mNativeApp;
3685 RefPtr<nsToolkitProfileService> mProfileSvc;
3686 nsCOMPtr<nsIFile> mProfD;
3687 nsCOMPtr<nsIFile> mProfLD;
3688 nsCOMPtr<nsIProfileLock> mProfileLock;
3689 #if defined(MOZ_HAS_REMOTE)
3690 RefPtr<nsRemoteService> mRemoteService;
3691 #endif
3693 UniquePtr<ScopedXPCOMStartup> mScopedXPCOM;
3694 UniquePtr<XREAppData> mAppData;
3696 nsXREDirProvider mDirProvider;
3698 #ifdef MOZ_WIDGET_GTK
3699 nsAutoCString mXDGActivationToken;
3700 nsAutoCString mDesktopStartupID;
3701 #endif
3703 bool mStartOffline = false;
3704 #if defined(MOZ_HAS_REMOTE)
3705 bool mDisableRemoteClient = false;
3706 bool mDisableRemoteServer = false;
3707 #endif
3710 #if defined(XP_UNIX) && !defined(ANDROID)
3711 static SmprintfPointer FormatUid(uid_t aId) {
3712 if (const auto pw = getpwuid(aId)) {
3713 return mozilla::Smprintf("%s", pw->pw_name);
3715 return mozilla::Smprintf("uid %d", static_cast<int>(aId));
3718 // Bug 1323302: refuse to run under sudo or similar.
3719 static bool CheckForUserMismatch() {
3720 static char const* const kVars[] = {
3721 "HOME",
3722 # ifdef MOZ_WIDGET_GTK
3723 "XDG_RUNTIME_DIR",
3724 # endif
3725 # ifdef MOZ_X11
3726 "XAUTHORITY",
3727 # endif
3730 const uid_t euid = geteuid();
3731 if (euid != 0) {
3732 // On Linux it's possible to have superuser capabilities with a
3733 // nonzero uid, but anyone who knows enough to make that happen
3734 // probably knows enough to debug the resulting problems.
3735 // Otherwise, a non-root user can't cause the problems we're
3736 // concerned about.
3737 return false;
3740 for (const auto var : kVars) {
3741 if (const auto path = PR_GetEnv(var)) {
3742 struct stat st;
3743 if (stat(path, &st) == 0) {
3744 if (st.st_uid != euid) {
3745 const auto owner = FormatUid(st.st_uid);
3746 Output(true,
3747 "Running " MOZ_APP_DISPLAYNAME
3748 " as root in a regular"
3749 " user's session is not supported. ($%s is %s which is"
3750 " owned by %s.)\n",
3751 var, path, owner.get());
3752 return true;
3757 return false;
3759 #else // !XP_UNIX || ANDROID
3760 static bool CheckForUserMismatch() { return false; }
3761 #endif
3763 void mozilla::startup::IncreaseDescriptorLimits() {
3764 #ifdef XP_UNIX
3765 // Increase the fd limit to accomodate IPC resources like shared memory.
3766 // See also the Darwin case in config/external/nspr/pr/moz.build
3767 static const rlim_t kFDs = 4096;
3768 struct rlimit rlim;
3770 if (getrlimit(RLIMIT_NOFILE, &rlim) != 0) {
3771 Output(false, "getrlimit: %s\n", strerror(errno));
3772 return;
3774 // Don't decrease the limit if it's already high enough, but don't
3775 // try to go over the hard limit. (RLIM_INFINITY isn't required to
3776 // be the numerically largest rlim_t, so don't assume that.)
3777 if (rlim.rlim_cur != RLIM_INFINITY && rlim.rlim_cur < kFDs &&
3778 rlim.rlim_cur < rlim.rlim_max) {
3779 if (rlim.rlim_max != RLIM_INFINITY && rlim.rlim_max < kFDs) {
3780 rlim.rlim_cur = rlim.rlim_max;
3781 } else {
3782 rlim.rlim_cur = kFDs;
3784 if (setrlimit(RLIMIT_NOFILE, &rlim) != 0) {
3785 Output(false, "setrlimit: %s\n", strerror(errno));
3788 #endif
3791 #ifdef XP_WIN
3793 static uint32_t GetMicrocodeVersionByVendor(HKEY key, DWORD upper,
3794 DWORD lower) {
3795 WCHAR data[13]; // The CPUID vendor string is 12 characters long plus null
3796 DWORD len = sizeof(data);
3797 DWORD vtype;
3799 if (RegQueryValueExW(key, L"VendorIdentifier", nullptr, &vtype,
3800 reinterpret_cast<LPBYTE>(data), &len) == ERROR_SUCCESS) {
3801 if (wcscmp(L"GenuineIntel", data) == 0) {
3802 // Intel reports the microcode version in the upper 32 bits of the MSR
3803 return upper;
3806 if (wcscmp(L"AuthenticAMD", data) == 0) {
3807 // AMD reports the microcode version in the lower 32 bits of the MSR
3808 return lower;
3811 // Unknown CPU vendor, return whatever half is non-zero
3812 return lower ? lower : upper;
3815 return 0; // No clue
3818 #endif // XP_WIN
3820 static void MaybeAddCPUMicrocodeCrashAnnotation() {
3821 #ifdef XP_WIN
3822 // Add CPU microcode version to the crash report as "CPUMicrocodeVersion".
3823 // It feels like this code may belong in nsSystemInfo instead.
3824 uint32_t cpuUpdateRevision = 0;
3825 HKEY key;
3826 static const WCHAR keyName[] =
3827 L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0";
3829 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, keyName, 0, KEY_QUERY_VALUE, &key) ==
3830 ERROR_SUCCESS) {
3831 DWORD updateRevision[2];
3832 DWORD len = sizeof(updateRevision);
3833 DWORD vtype;
3835 // Windows 7 uses "Update Signature", 8 uses "Update Revision".
3836 // For AMD CPUs, "CurrentPatchLevel" is sometimes used.
3837 // Take the first one we find.
3838 LPCWSTR choices[] = {L"Update Signature", L"Update Revision",
3839 L"CurrentPatchLevel"};
3840 for (const auto& oneChoice : choices) {
3841 if (RegQueryValueExW(key, oneChoice, nullptr, &vtype,
3842 reinterpret_cast<LPBYTE>(updateRevision),
3843 &len) == ERROR_SUCCESS) {
3844 if (vtype == REG_BINARY && len == sizeof(updateRevision)) {
3845 cpuUpdateRevision = GetMicrocodeVersionByVendor(
3846 key, updateRevision[1], updateRevision[0]);
3847 break;
3850 if (vtype == REG_DWORD && len == sizeof(updateRevision[0])) {
3851 cpuUpdateRevision = static_cast<int>(updateRevision[0]);
3852 break;
3858 if (cpuUpdateRevision > 0) {
3859 CrashReporter::RecordAnnotationNSCString(
3860 CrashReporter::Annotation::CPUMicrocodeVersion,
3861 nsPrintfCString("0x%" PRIx32, cpuUpdateRevision));
3863 #endif
3866 #if defined(MOZ_BACKGROUNDTASKS)
3867 static void SetupConsoleForBackgroundTask(
3868 const nsCString& aBackgroundTaskName) {
3869 // We do not suppress output on Windows because:
3870 // 1. Background task subprocesses launched via LaunchApp() does not attach to
3871 // the console.
3872 // 2. Suppressing output intermittently causes failures on when running
3873 // multiple tasks (see bug 1831631)
3874 # ifndef XP_WIN
3875 if (BackgroundTasks::IsNoOutputTaskName(aBackgroundTaskName) &&
3876 !CheckArg("attach-console") &&
3877 !EnvHasValue("MOZ_BACKGROUNDTASKS_IGNORE_NO_OUTPUT")) {
3878 // Suppress output, somewhat crudely. We need to suppress stderr as well
3879 // as stdout because assertions, of which there are many, write to stderr.
3880 Unused << freopen("/dev/null", "w", stdout);
3881 Unused << freopen("/dev/null", "w", stderr);
3882 return;
3884 # endif
3885 printf_stderr("*** You are running in background task mode. ***\n");
3887 #endif
3890 * XRE_mainInit - Initial setup and command line parameter processing.
3891 * Main() will exit early if either return value != 0 or if aExitFlag is
3892 * true.
3894 int XREMain::XRE_mainInit(bool* aExitFlag) {
3895 if (!aExitFlag) return 1;
3896 *aExitFlag = false;
3898 atexit(UnexpectedExit);
3899 auto expectedShutdown = mozilla::MakeScopeExit([&] { MozExpectedExit(); });
3901 StartupTimeline::Record(StartupTimeline::MAIN);
3903 if (CheckForUserMismatch()) {
3904 return 1;
3907 #ifdef XP_MACOSX
3908 mozilla::MacAutoreleasePool pool;
3910 DisableAppNap();
3911 #endif
3913 #ifdef MOZ_BACKGROUNDTASKS
3914 Maybe<nsCString> backgroundTask = Nothing();
3915 const char* backgroundTaskName = nullptr;
3916 if (ARG_FOUND ==
3917 CheckArg("backgroundtask", &backgroundTaskName, CheckArgFlag::None)) {
3918 backgroundTask = Some(backgroundTaskName);
3920 SetupConsoleForBackgroundTask(backgroundTask.ref());
3923 BackgroundTasks::Init(backgroundTask);
3924 #endif
3926 #ifndef ANDROID
3927 if (PR_GetEnv("MOZ_RUN_GTEST")
3928 # ifdef FUZZING
3929 || PR_GetEnv("FUZZER")
3930 # endif
3931 # ifdef MOZ_BACKGROUNDTASKS
3932 || BackgroundTasks::IsBackgroundTaskMode()
3933 # endif
3935 // Enable headless mode and assert that it worked, since gfxPlatform
3936 // uses a static bool set after the first call to `IsHeadless`.
3937 // Note: Android gtests seem to require an Activity and fail to start
3938 // with headless mode enabled.
3939 PR_SetEnv("MOZ_HEADLESS=1");
3940 MOZ_ASSERT(gfxPlatform::IsHeadless());
3942 #endif // ANDROID
3944 if (PR_GetEnv("MOZ_CHAOSMODE")) {
3945 ChaosFeature feature = ChaosFeature::Any;
3946 long featureInt = strtol(PR_GetEnv("MOZ_CHAOSMODE"), nullptr, 16);
3947 if (featureInt) {
3948 // NOTE: MOZ_CHAOSMODE=0 or a non-hex value maps to Any feature.
3949 feature = static_cast<ChaosFeature>(featureInt);
3951 ChaosMode::SetChaosFeature(feature);
3954 if (CheckArgExists("fxr")) {
3955 gFxREmbedded = true;
3958 if (ChaosMode::isActive(ChaosFeature::Any)) {
3959 printf_stderr(
3960 "*** You are running in chaos test mode. See ChaosMode.h. ***\n");
3963 if (CheckArg("headless") || CheckArgExists("screenshot")) {
3964 PR_SetEnv("MOZ_HEADLESS=1");
3967 if (gfxPlatform::IsHeadless()) {
3968 #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) || defined(XP_MACOSX)
3969 printf_stderr("*** You are running in headless mode.\n");
3970 #else
3971 Output(
3972 true,
3973 "Error: headless mode is not currently supported on this platform.\n");
3974 return 1;
3975 #endif
3977 #ifdef XP_MACOSX
3978 // To avoid taking focus when running in headless mode immediately
3979 // transition Firefox to a background application.
3980 ProcessSerialNumber psn = {0, kCurrentProcess};
3981 OSStatus transformStatus =
3982 TransformProcessType(&psn, kProcessTransformToBackgroundApplication);
3983 if (transformStatus != noErr) {
3984 NS_ERROR("Failed to make process a background application.");
3985 return 1;
3987 #endif
3990 gKioskMode = CheckArg("kiosk", nullptr, CheckArgFlag::None);
3991 const char* kioskMonitorNumber = nullptr;
3992 if (CheckArg("kiosk-monitor", &kioskMonitorNumber, CheckArgFlag::None)) {
3993 gKioskMode = true;
3994 gKioskMonitor = atoi(kioskMonitorNumber);
3997 gAllowContentAnalysisArgPresent =
3998 CheckArg("allow-content-analysis", nullptr, CheckArgFlag::RemoveArg) ==
3999 ARG_FOUND;
4001 nsresult rv;
4002 ArgResult ar;
4004 #ifdef DEBUG
4005 if (PR_GetEnv("XRE_MAIN_BREAK")) NS_BREAK();
4006 #endif
4008 mozilla::startup::IncreaseDescriptorLimits();
4010 SetupErrorHandling(gArgv[0]);
4012 #ifdef CAIRO_HAS_DWRITE_FONT
4014 // Bug 602792 - when DWriteCreateFactory is called the dwrite client dll
4015 // starts the FntCache service if it isn't already running (it's set
4016 // to manual startup by default in Windows 7 RTM). Subsequent DirectWrite
4017 // calls cause the IDWriteFactory object to communicate with the FntCache
4018 // service with a timeout; if there's no response after the timeout, the
4019 // DirectWrite client library will assume the service isn't around and do
4020 // manual font file I/O on _all_ system fonts. To avoid this, load the
4021 // dwrite library and create a factory as early as possible so that the
4022 // FntCache service is ready by the time it's needed.
4024 CreateThread(nullptr, 0, &InitDwriteBG, nullptr, 0, nullptr);
4026 #endif
4028 #ifdef XP_UNIX
4029 const char* home = PR_GetEnv("HOME");
4030 if (!home || !*home) {
4031 struct passwd* pw = getpwuid(geteuid());
4032 if (!pw || !pw->pw_dir) {
4033 Output(true, "Could not determine HOME directory");
4034 return 1;
4036 SaveWordToEnv("HOME", nsDependentCString(pw->pw_dir));
4038 #endif
4040 #ifdef MOZ_ACCESSIBILITY_ATK
4041 // Suppress atk-bridge init at startup, until mozilla accessibility is
4042 // initialized. This works after gnome 2.24.2.
4043 SaveToEnv("NO_AT_BRIDGE=1");
4044 #endif
4046 // Check for application.ini overrides
4047 const char* override = nullptr;
4048 ar = CheckArg("override", &override);
4049 if (ar == ARG_BAD) {
4050 Output(true, "Incorrect number of arguments passed to --override");
4051 return 1;
4053 if (ar == ARG_FOUND) {
4054 nsCOMPtr<nsIFile> overrideLF;
4055 rv = XRE_GetFileFromPath(override, getter_AddRefs(overrideLF));
4056 if (NS_FAILED(rv)) {
4057 Output(true, "Error: unrecognized override.ini path.\n");
4058 return 1;
4061 rv = XRE_ParseAppData(overrideLF, *mAppData);
4062 if (NS_FAILED(rv)) {
4063 Output(true, "Couldn't read override.ini");
4064 return 1;
4068 // Check sanity and correctness of app data.
4070 if (!mAppData->name) {
4071 Output(true, "Error: App:Name not specified in application.ini\n");
4072 return 1;
4074 if (!mAppData->buildID) {
4075 Output(true, "Error: App:BuildID not specified in application.ini\n");
4076 return 1;
4079 // XXX Originally ScopedLogging was here? Now it's in XRE_main above
4080 // XRE_mainInit.
4082 if (!mAppData->minVersion) {
4083 Output(true, "Error: Gecko:MinVersion not specified in application.ini\n");
4084 return 1;
4087 if (!mAppData->maxVersion) {
4088 // If no maxVersion is specified, we assume the app is only compatible
4089 // with the initial preview release. Do not increment this number ever!
4090 mAppData->maxVersion = "1.*";
4093 if (mozilla::Version(mAppData->minVersion) > gToolkitVersion ||
4094 mozilla::Version(mAppData->maxVersion) < gToolkitVersion) {
4095 Output(true,
4096 "Error: Platform version '%s' is not compatible with\n"
4097 "minVersion >= %s\nmaxVersion <= %s\n",
4098 (const char*)gToolkitVersion, (const char*)mAppData->minVersion,
4099 (const char*)mAppData->maxVersion);
4100 return 1;
4103 rv = mDirProvider.Initialize(mAppData->directory, mAppData->xreDirectory);
4104 if (NS_FAILED(rv)) return 1;
4106 if (EnvHasValue("MOZ_CRASHREPORTER")) {
4107 mAppData->flags |= NS_XRE_ENABLE_CRASH_REPORTER;
4110 nsCOMPtr<nsIFile> xreBinDirectory;
4111 xreBinDirectory = mDirProvider.GetGREBinDir();
4113 if ((mAppData->flags & NS_XRE_ENABLE_CRASH_REPORTER) &&
4114 NS_SUCCEEDED(CrashReporter::SetExceptionHandler(xreBinDirectory))) {
4115 nsCOMPtr<nsIFile> file;
4116 rv = nsXREDirProvider::GetUserAppDataDirectory(getter_AddRefs(file));
4117 if (NS_SUCCEEDED(rv)) {
4118 CrashReporter::SetUserAppDataDirectory(file);
4120 if (mAppData->crashReporterURL) {
4121 CrashReporter::SetServerURL(
4122 nsDependentCString(mAppData->crashReporterURL));
4125 // We overwrite this once we finish starting up.
4126 CrashReporter::RecordAnnotationBool(CrashReporter::Annotation::StartupCrash,
4127 true);
4129 // pass some basic info from the app data
4130 if (mAppData->vendor) {
4131 CrashReporter::RecordAnnotationCString(CrashReporter::Annotation::Vendor,
4132 mAppData->vendor);
4134 if (mAppData->name) {
4135 CrashReporter::RecordAnnotationCString(
4136 CrashReporter::Annotation::ProductName, mAppData->name);
4138 if (mAppData->ID) {
4139 CrashReporter::RecordAnnotationCString(
4140 CrashReporter::Annotation::ProductID, mAppData->ID);
4142 if (mAppData->version) {
4143 CrashReporter::RecordAnnotationCString(CrashReporter::Annotation::Version,
4144 mAppData->version);
4146 if (mAppData->buildID) {
4147 CrashReporter::RecordAnnotationCString(CrashReporter::Annotation::BuildID,
4148 mAppData->buildID);
4151 nsDependentCString releaseChannel(MOZ_STRINGIFY(MOZ_UPDATE_CHANNEL));
4152 CrashReporter::RecordAnnotationNSCString(
4153 CrashReporter::Annotation::ReleaseChannel, releaseChannel);
4155 #ifdef XP_WIN
4156 nsAutoString appInitDLLs;
4157 if (widget::WinUtils::GetAppInitDLLs(appInitDLLs)) {
4158 CrashReporter::RecordAnnotationNSString(
4159 CrashReporter::Annotation::AppInitDLLs, appInitDLLs);
4162 nsString packageFamilyName = widget::WinUtils::GetPackageFamilyName();
4163 if (StringBeginsWith(packageFamilyName, u"Mozilla."_ns) ||
4164 StringBeginsWith(packageFamilyName, u"MozillaCorporation."_ns)) {
4165 CrashReporter::RecordAnnotationNSCString(
4166 CrashReporter::Annotation::WindowsPackageFamilyName,
4167 NS_ConvertUTF16toUTF8(packageFamilyName));
4169 #endif
4171 bool isBackgroundTaskMode = false;
4172 #ifdef MOZ_BACKGROUNDTASKS
4173 Maybe<nsCString> backgroundTasks = BackgroundTasks::GetBackgroundTasks();
4174 if (backgroundTasks.isSome()) {
4175 isBackgroundTaskMode = true;
4176 CrashReporter::RecordAnnotationNSCString(
4177 CrashReporter::Annotation::BackgroundTaskName, backgroundTasks.ref());
4179 #endif
4180 CrashReporter::RecordAnnotationBool(
4181 CrashReporter::Annotation::BackgroundTaskMode, isBackgroundTaskMode);
4183 CrashReporter::RecordAnnotationBool(CrashReporter::Annotation::HeadlessMode,
4184 gfxPlatform::IsHeadless());
4186 CrashReporter::SetRestartArgs(gArgc, gArgv);
4188 // annotate other data (user id etc)
4189 nsCOMPtr<nsIFile> userAppDataDir;
4190 if (NS_SUCCEEDED(mDirProvider.GetUserAppDataDirectory(
4191 getter_AddRefs(userAppDataDir)))) {
4192 CrashReporter::SetupExtraData(userAppDataDir,
4193 nsDependentCString(mAppData->buildID));
4195 // see if we have a crashreporter-override.ini in the application
4196 // directory
4197 nsCOMPtr<nsIFile> overrideini;
4198 if (NS_SUCCEEDED(
4199 mDirProvider.GetAppDir()->Clone(getter_AddRefs(overrideini))) &&
4200 NS_SUCCEEDED(
4201 overrideini->AppendNative("crashreporter-override.ini"_ns))) {
4202 #ifdef XP_WIN
4203 nsAutoString overridePathW;
4204 overrideini->GetPath(overridePathW);
4205 NS_ConvertUTF16toUTF8 overridePath(overridePathW);
4206 #else
4207 nsAutoCString overridePath;
4208 overrideini->GetNativePath(overridePath);
4209 #endif
4211 SaveWordToEnv("MOZ_CRASHREPORTER_STRINGS_OVERRIDE", overridePath);
4214 } else {
4215 // We might have registered a runtime exception module very early in process
4216 // startup to catch early crashes. This is before we have access to ini file
4217 // data, so unregister here if it turns out the crash reporter is disabled.
4218 CrashReporter::UnregisterRuntimeExceptionModule();
4221 #if defined(MOZ_SANDBOX) && defined(XP_WIN)
4222 if (mAppData->sandboxBrokerServices) {
4223 nsAutoString binDirPath;
4224 MOZ_ALWAYS_SUCCEEDS(xreBinDirectory->GetPath(binDirPath));
4225 SandboxBroker::Initialize(mAppData->sandboxBrokerServices, binDirPath);
4226 } else {
4227 # if defined(MOZ_SANDBOX)
4228 // If we're sandboxing content and we fail to initialize, then crashing here
4229 // seems like the sensible option.
4230 if (BrowserTabsRemoteAutostart()) {
4231 MOZ_CRASH("Failed to initialize broker services, can't continue.");
4233 # endif
4234 // Otherwise just warn for the moment, as most things will work.
4235 NS_WARNING(
4236 "Failed to initialize broker services, sandboxed processes will "
4237 "fail to start.");
4239 #endif
4241 #ifdef XP_MACOSX
4242 // Set up ability to respond to system (Apple) events. This must occur before
4243 // ProcessUpdates to ensure that links clicked in external applications aren't
4244 // lost when updates are pending.
4245 SetupMacApplicationDelegate(&gRestartedByOS);
4247 if (EnvHasValue("MOZ_LAUNCHED_CHILD")) {
4248 // This is needed, on relaunch, to force the OS to use the "Cocoa Dock
4249 // API". Otherwise the call to ReceiveNextEvent() below will make it
4250 // use the "Carbon Dock API". For more info see bmo bug 377166.
4251 EnsureUseCocoaDockAPI();
4253 // When the app relaunches, the original process exits. This causes
4254 // the dock tile to stop bouncing, lose the "running" triangle, and
4255 // if the tile does not permanently reside in the Dock, even disappear.
4256 // This can be confusing to the user, who is expecting the app to launch.
4257 // Calling ReceiveNextEvent without requesting any event is enough to
4258 // cause a dock tile for the child process to appear.
4259 const EventTypeSpec kFakeEventList[] = {{INT_MAX, INT_MAX}};
4260 EventRef event;
4261 ::ReceiveNextEvent(GetEventTypeCount(kFakeEventList), kFakeEventList,
4262 kEventDurationNoWait, false, &event);
4265 if (CheckArg("foreground")) {
4266 // The original process communicates that it was in the foreground by
4267 // adding this argument. This new process, which is taking over for
4268 // the old one, should make itself the active application.
4269 ProcessSerialNumber psn;
4270 if (::GetCurrentProcess(&psn) == noErr) ::SetFrontProcess(&psn);
4272 #endif
4274 SaveToEnv("MOZ_LAUNCHED_CHILD=");
4276 // On Windows, the -os-restarted command line switch lets us know when we are
4277 // restarted via RegisterApplicationRestart. May be used for other OSes later.
4278 if (CheckArg("os-restarted", nullptr, CheckArgFlag::RemoveArg) == ARG_FOUND) {
4279 gRestartedByOS = true;
4282 gRestartArgc = gArgc;
4283 gRestartArgv =
4284 (char**)malloc(sizeof(char*) * (gArgc + 1 + (override ? 2 : 0)));
4285 if (!gRestartArgv) {
4286 return 1;
4289 int i;
4290 for (i = 0; i < gArgc; ++i) {
4291 gRestartArgv[i] = gArgv[i];
4294 // Add the -override argument back (it is removed automatically be CheckArg)
4295 // if there is one
4296 if (override) {
4297 gRestartArgv[gRestartArgc++] = const_cast<char*>("-override");
4298 gRestartArgv[gRestartArgc++] = const_cast<char*>(override);
4301 gRestartArgv[gRestartArgc] = nullptr;
4303 Maybe<bool> safeModeRequested = IsSafeModeRequested(gArgc, gArgv);
4304 if (!safeModeRequested) {
4305 return 1;
4307 #ifdef MOZ_BACKGROUNDTASKS
4308 if (BackgroundTasks::IsBackgroundTaskMode()) {
4309 safeModeRequested = Some(false);
4311 // Remove the --backgroundtask arg now that it has been saved in
4312 // gRestartArgv.
4313 const char* tmpBackgroundTaskName = nullptr;
4314 Unused << CheckArg("backgroundtask", &tmpBackgroundTaskName,
4315 CheckArgFlag::RemoveArg);
4317 #endif
4319 gSafeMode = safeModeRequested.value();
4321 MaybeAddCPUMicrocodeCrashAnnotation();
4322 CrashReporter::RegisterAnnotationBool(CrashReporter::Annotation::SafeMode,
4323 &gSafeMode);
4325 #if defined(MOZ_HAS_REMOTE)
4326 // Handle --no-remote and --new-instance command line arguments. Setup
4327 // the environment to better accommodate other components and various
4328 // restart scenarios.
4329 ar = CheckArg("no-remote");
4330 if (ar == ARG_FOUND || EnvHasValue("MOZ_NO_REMOTE")) {
4331 mDisableRemoteClient = true;
4332 mDisableRemoteServer = true;
4333 gRestartWithoutRemote = true;
4334 // We don't want to propagate MOZ_NO_REMOTE to potential child
4335 // process.
4336 SaveToEnv("MOZ_NO_REMOTE=");
4339 ar = CheckArg("new-instance");
4340 if (ar == ARG_FOUND || EnvHasValue("MOZ_NEW_INSTANCE")) {
4341 mDisableRemoteClient = true;
4343 #else
4344 // These arguments do nothing in platforms with no remoting support but we
4345 // should remove them from the command line anyway.
4346 CheckArg("no-remote");
4347 CheckArg("new-instance");
4348 #endif
4350 ar = CheckArg("offline");
4351 if (ar || EnvHasValue("XRE_START_OFFLINE")) {
4352 mStartOffline = true;
4355 // On Windows, to get working console arrangements so help/version/etc
4356 // print something, we need to initialize the native app support.
4357 rv = NS_CreateNativeAppSupport(getter_AddRefs(mNativeApp));
4358 if (NS_FAILED(rv)) return 1;
4360 // Handle --help, --full-version and --version command line arguments.
4361 // They should return quickly, so we deal with them here.
4362 if (CheckArg("h") || CheckArg("help") || CheckArg("?")) {
4363 DumpHelp();
4364 *aExitFlag = true;
4365 return 0;
4368 if (CheckArg("v") || CheckArg("version")) {
4369 DumpVersion();
4370 *aExitFlag = true;
4371 return 0;
4374 if (CheckArg("full-version")) {
4375 DumpFullVersion();
4376 *aExitFlag = true;
4377 return 0;
4380 rv = XRE_InitCommandLine(gArgc, gArgv);
4381 NS_ENSURE_SUCCESS(rv, 1);
4383 return 0;
4386 #if defined(XP_LINUX) && !defined(ANDROID)
4388 static void AnnotateLSBRelease(void*) {
4389 nsCString dist, desc, release, codename;
4390 if (widget::lsb::GetLSBRelease(dist, desc, release, codename)) {
4391 CrashReporter::AppendAppNotesToCrashReport(desc);
4395 #endif // defined(XP_LINUX) && !defined(ANDROID)
4397 #ifdef XP_WIN
4398 static void ReadAheadSystemDll(const wchar_t* dllName) {
4399 wchar_t dllPath[MAX_PATH];
4400 if (ConstructSystem32Path(dllName, dllPath, MAX_PATH)) {
4401 ReadAheadLib(dllPath);
4405 static void ReadAheadPackagedDll(const wchar_t* dllName,
4406 const wchar_t* aGREDir) {
4407 wchar_t dllPath[MAX_PATH];
4408 swprintf(dllPath, MAX_PATH, L"%s\\%s", aGREDir, dllName);
4409 ReadAheadLib(dllPath);
4412 static void PR_CALLBACK ReadAheadDlls_ThreadStart(void* arg) {
4413 UniquePtr<wchar_t[]> greDir(static_cast<wchar_t*>(arg));
4415 // In Bug 1628903, we investigated which DLLs we should prefetch in
4416 // order to reduce disk I/O and improve startup on Windows machines.
4417 // Our ultimate goal is to measure the impact of these improvements on
4418 // retention (see Bug 1640087). Before we place this within a pref,
4419 // we should ensure this feature only ships to the nightly channel
4420 // and monitor results from that subset.
4421 if (greDir) {
4422 // Prefetch the DLLs shipped with firefox
4423 ReadAheadPackagedDll(L"libegl.dll", greDir.get());
4424 ReadAheadPackagedDll(L"libGLESv2.dll", greDir.get());
4425 ReadAheadPackagedDll(L"nssckbi.dll", greDir.get());
4426 ReadAheadPackagedDll(L"freebl3.dll", greDir.get());
4427 ReadAheadPackagedDll(L"softokn3.dll", greDir.get());
4429 // Prefetch the system DLLs
4430 ReadAheadSystemDll(L"DWrite.dll");
4431 ReadAheadSystemDll(L"D3DCompiler_47.dll");
4432 } else {
4433 // Load DataExchange.dll and twinapi.appcore.dll for
4434 // nsWindow::EnableDragDrop
4435 ReadAheadSystemDll(L"DataExchange.dll");
4436 ReadAheadSystemDll(L"twinapi.appcore.dll");
4438 // Load twinapi.dll for WindowsUIUtils::UpdateTabletModeState
4439 ReadAheadSystemDll(L"twinapi.dll");
4441 // Load explorerframe.dll for WinTaskbar::Initialize
4442 ReadAheadSystemDll(L"ExplorerFrame.dll");
4444 // Load WinTypes.dll for nsOSHelperAppService::GetApplicationDescription
4445 ReadAheadSystemDll(L"WinTypes.dll");
4448 #endif
4450 #if defined(MOZ_UPDATER) && !defined(MOZ_WIDGET_ANDROID)
4451 enum struct ShouldNotProcessUpdatesReason {
4452 DevToolsLaunching,
4453 NotAnUpdatingTask,
4454 OtherInstanceRunning,
4455 FirstStartup
4458 const char* ShouldNotProcessUpdatesReasonAsString(
4459 ShouldNotProcessUpdatesReason aReason) {
4460 switch (aReason) {
4461 case ShouldNotProcessUpdatesReason::DevToolsLaunching:
4462 return "DevToolsLaunching";
4463 case ShouldNotProcessUpdatesReason::NotAnUpdatingTask:
4464 return "NotAnUpdatingTask";
4465 case ShouldNotProcessUpdatesReason::OtherInstanceRunning:
4466 return "OtherInstanceRunning";
4467 default:
4468 MOZ_CRASH("impossible value for ShouldNotProcessUpdatesReason");
4472 Maybe<ShouldNotProcessUpdatesReason> ShouldNotProcessUpdates(
4473 nsXREDirProvider& aDirProvider) {
4474 // Don't process updates when launched from the installer.
4475 // It's possible for a stale update to be present in the case of a paveover;
4476 // ignore it and leave the update service to discard it.
4477 if (ARG_FOUND == CheckArgExists("first-startup")) {
4478 NS_WARNING("ShouldNotProcessUpdates(): FirstStartup");
4479 return Some(ShouldNotProcessUpdatesReason::FirstStartup);
4482 // Do not process updates if we're launching devtools, as evidenced by
4483 // "--chrome ..." with the browser toolbox chrome document URL.
4485 // Keep this synchronized with the value of the same name in
4486 // devtools/client/framework/browser-toolbox/Launcher.sys.mjs. Or, for bonus
4487 // points, lift this value to nsIXulRuntime or similar, so that it can be
4488 // accessed in both locations. (The prefs service isn't available at this
4489 // point so the simplest manner of sharing the value is not available to us.)
4490 const char* BROWSER_TOOLBOX_WINDOW_URL =
4491 "chrome://devtools/content/framework/browser-toolbox/window.html";
4493 const char* chromeParam = nullptr;
4494 if (ARG_FOUND == CheckArg("chrome", &chromeParam, CheckArgFlag::None)) {
4495 if (!chromeParam || !strcmp(BROWSER_TOOLBOX_WINDOW_URL, chromeParam)) {
4496 NS_WARNING("ShouldNotProcessUpdates(): DevToolsLaunching");
4497 return Some(ShouldNotProcessUpdatesReason::DevToolsLaunching);
4501 # ifdef MOZ_BACKGROUNDTASKS
4502 // Do not process updates if we're running a background task mode and another
4503 // instance is already running. This avoids periodic maintenance updating
4504 // underneath a browsing session.
4505 Maybe<nsCString> backgroundTasks = BackgroundTasks::GetBackgroundTasks();
4506 if (backgroundTasks.isSome()) {
4507 // Only process updates for specific tasks: at this time, the
4508 // `backgroundupdate` task and the test-only `shouldprocessupdates` task.
4510 // Background tasks can be sparked by Firefox instances that are shutting
4511 // down, which can cause races between the task startup trying to update and
4512 // Firefox trying to invoke the updater. This happened when converting
4513 // `pingsender` to a background task, since it is launched to send pings at
4514 // shutdown: Bug 1736373.
4516 // We'd prefer to have this be a property of the task definition sibling to
4517 // `backgroundTaskTimeoutSec`, but when we reach this code we're well before
4518 // we can load the task JSM.
4519 if (!BackgroundTasks::IsUpdatingTaskName(backgroundTasks.ref())) {
4520 NS_WARNING("ShouldNotProcessUpdates(): NotAnUpdatingTask");
4521 return Some(ShouldNotProcessUpdatesReason::NotAnUpdatingTask);
4524 // At this point we have a dir provider but no XPCOM directory service. We
4525 // launch the update sync manager using that information so that it doesn't
4526 // need to ask for (and fail to find) the directory service.
4527 nsCOMPtr<nsIFile> anAppFile;
4528 bool persistent;
4529 nsresult rv = aDirProvider.GetFile(XRE_EXECUTABLE_FILE, &persistent,
4530 getter_AddRefs(anAppFile));
4531 if (NS_FAILED(rv) || !anAppFile) {
4532 // Strange, but not a reason to skip processing updates.
4533 return Nothing();
4536 auto updateSyncManager = new nsUpdateSyncManager(anAppFile);
4538 bool otherInstance = false;
4539 updateSyncManager->IsOtherInstanceRunning(&otherInstance);
4540 if (otherInstance) {
4541 NS_WARNING("ShouldNotProcessUpdates(): OtherInstanceRunning");
4542 return Some(ShouldNotProcessUpdatesReason::OtherInstanceRunning);
4545 # endif
4547 return Nothing();
4549 #endif
4551 namespace mozilla::startup {
4552 Result<nsCOMPtr<nsIFile>, nsresult> GetIncompleteStartupFile(nsIFile* aProfLD) {
4553 nsCOMPtr<nsIFile> crashFile;
4554 MOZ_TRY(aProfLD->Clone(getter_AddRefs(crashFile)));
4555 MOZ_TRY(crashFile->Append(FILE_STARTUP_INCOMPLETE));
4556 return std::move(crashFile);
4558 } // namespace mozilla::startup
4560 // Check whether the last startup attempt resulted in a crash or hang.
4561 // This is distinct from the definition of a startup crash from
4562 // nsAppStartup::TrackStartupCrashBegin.
4563 bool XREMain::CheckLastStartupWasCrash() {
4564 Result<nsCOMPtr<nsIFile>, nsresult> crashFile =
4565 GetIncompleteStartupFile(mProfLD);
4566 if (crashFile.isErr()) {
4567 return true;
4570 // Attempt to create the incomplete startup canary file. If the file already
4571 // exists, this fails, and we know the last startup was a crash. If it
4572 // doesn't already exist, it is created, and will be removed at the end of
4573 // the startup crash detection window.
4574 AutoFDClose fd;
4575 Unused << crashFile.inspect()->OpenNSPRFileDesc(
4576 PR_WRONLY | PR_CREATE_FILE | PR_EXCL, 0666, getter_Transfers(fd));
4577 return !fd;
4581 * XRE_mainStartup - Initializes the profile and various other services.
4582 * Main() will exit early if either return value != 0 or if aExitFlag is
4583 * true.
4585 int XREMain::XRE_mainStartup(bool* aExitFlag) {
4586 nsresult rv;
4588 if (!aExitFlag) return 1;
4589 *aExitFlag = false;
4591 #ifdef XP_MACOSX
4592 mozilla::MacAutoreleasePool pool;
4593 #endif
4595 // Enable Telemetry IO Reporting on DEBUG, nightly and local builds,
4596 // but disable it on FUZZING builds and for ANDROID.
4597 #ifndef FUZZING
4598 # ifndef ANDROID
4599 # ifdef DEBUG
4600 mozilla::Telemetry::InitIOReporting(gAppData->xreDirectory);
4601 # else
4603 const char* releaseChannel = MOZ_STRINGIFY(MOZ_UPDATE_CHANNEL);
4604 if (strcmp(releaseChannel, "nightly") == 0 ||
4605 strcmp(releaseChannel, "default") == 0) {
4606 mozilla::Telemetry::InitIOReporting(gAppData->xreDirectory);
4609 # endif /* DEBUG */
4610 # endif /* ANDROID */
4611 #endif /* FUZZING */
4613 #if defined(XP_WIN)
4614 // Enable the HeapEnableTerminationOnCorruption exploit mitigation. We ignore
4615 // the return code because it always returns success, although it has no
4616 // effect on Windows older than XP SP3.
4617 HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);
4618 #endif /* XP_WIN */
4620 #ifdef MOZ_WIDGET_GTK
4621 // Stash startup token in owned memory because gtk_init will clear
4622 // DESKTOP_STARTUP_ID it.
4623 if (const char* v = PR_GetEnv("DESKTOP_STARTUP_ID")) {
4624 mDesktopStartupID.Assign(v);
4626 if (const char* v = PR_GetEnv("XDG_ACTIVATION_TOKEN")) {
4627 mXDGActivationToken.Assign(v);
4629 #endif
4631 #if defined(XP_WIN)
4633 // Save the shortcut path before lpTitle is replaced by an AUMID,
4634 // such as by WinTaskbar
4635 STARTUPINFOW si;
4636 GetStartupInfoW(&si);
4637 if (si.dwFlags & STARTF_TITLEISAPPID) {
4638 NS_WARNING("AUMID was already set, shortcut may have been lost.");
4639 } else if ((si.dwFlags & STARTF_TITLEISLINKNAME) && si.lpTitle) {
4640 gProcessStartupShortcut.Assign(si.lpTitle);
4643 #endif /* XP_WIN */
4645 #if defined(MOZ_WIDGET_GTK)
4646 // setup for private colormap. Ideally we'd like to do this
4647 // in nsAppShell::Create, but we need to get in before gtk
4648 // has been initialized to make sure everything is running
4649 // consistently.
4651 // Set program name to the one defined in application.ini.
4652 g_set_prgname(gAppData->remotingName);
4654 // Initialize GTK here for splash.
4656 # if defined(MOZ_WIDGET_GTK) && defined(MOZ_X11)
4657 // Disable XInput2 multidevice support due to focus bugginess.
4658 // See bugs 1182700, 1170342.
4659 // gdk_disable_multidevice() affects Gdk X11 backend only,
4660 // the multidevice support is always enabled on Wayland backend.
4661 const char* useXI2 = PR_GetEnv("MOZ_USE_XINPUT2");
4662 if (!useXI2 || (*useXI2 == '0')) gdk_disable_multidevice();
4663 # endif
4665 // Open the display ourselves instead of using gtk_init, so that we can
4666 // close it without fear that one day gtk might clean up the display it
4667 // opens.
4668 if (!gtk_parse_args(&gArgc, &gArgv)) return 1;
4669 #endif /* MOZ_WIDGET_GTK */
4671 #ifdef FUZZING
4672 if (PR_GetEnv("FUZZER")) {
4673 *aExitFlag = true;
4674 return mozilla::fuzzerRunner->Run(&gArgc, &gArgv);
4676 #endif
4678 if (PR_GetEnv("MOZ_RUN_GTEST")) {
4679 int result;
4680 #ifdef XP_WIN
4681 UseParentConsole();
4682 #endif
4683 // RunGTest will only be set if we're in xul-unit
4684 if (mozilla::RunGTest) {
4685 gIsGtest = true;
4686 result = mozilla::RunGTest(&gArgc, gArgv);
4687 gIsGtest = false;
4688 } else {
4689 result = 1;
4690 printf("TEST-UNEXPECTED-FAIL | gtest | Not compiled with enable-tests\n");
4692 *aExitFlag = true;
4693 return result;
4696 bool isBackgroundTaskMode = false;
4697 #ifdef MOZ_BACKGROUNDTASKS
4698 isBackgroundTaskMode = BackgroundTasks::IsBackgroundTaskMode();
4699 #endif
4701 #ifdef MOZ_HAS_REMOTE
4702 if (gfxPlatform::IsHeadless()) {
4703 mDisableRemoteClient = true;
4704 mDisableRemoteServer = true;
4706 #endif
4708 #ifdef MOZ_X11
4709 // Init X11 in thread-safe mode. Must be called prior to the first call to
4710 // XOpenDisplay (called inside gdk_display_open). This is a requirement for
4711 // off main tread compositing.
4712 if (!isBackgroundTaskMode && !gfxPlatform::IsHeadless()) {
4713 XInitThreads();
4715 #endif
4716 #if defined(MOZ_WIDGET_GTK)
4717 if (!isBackgroundTaskMode && !gfxPlatform::IsHeadless()) {
4718 const char* display_name = nullptr;
4719 bool saveDisplayArg = false;
4721 // display_name is owned by gdk.
4722 display_name = gdk_get_display_arg_name();
4723 bool waylandEnabled = IsWaylandEnabled();
4724 # ifdef MOZ_WAYLAND
4725 if (!display_name) {
4726 auto* proxyEnv = getenv("MOZ_DISABLE_WAYLAND_PROXY");
4727 bool disableWaylandProxy = proxyEnv && *proxyEnv;
4728 if (!disableWaylandProxy && XRE_IsParentProcess() && waylandEnabled) {
4729 # ifdef MOZ_LOGGING
4730 if (MOZ_LOG_TEST(gWidgetWaylandLog, mozilla::LogLevel::Debug)) {
4731 WaylandProxy::SetVerbose(true);
4733 # endif
4734 gWaylandProxy = WaylandProxy::Create();
4735 if (gWaylandProxy) {
4736 gWaylandProxy->RunThread();
4740 # endif
4742 // if --display argument is given make sure it's
4743 // also passed to ContentChild::Init() by MOZ_GDK_DISPLAY.
4744 if (display_name) {
4745 SaveWordToEnv("MOZ_GDK_DISPLAY", nsDependentCString(display_name));
4746 saveDisplayArg = true;
4749 // On Wayland disabled builds read X11 DISPLAY env exclusively
4750 // and don't care about different displays.
4751 if (!waylandEnabled && !display_name) {
4752 display_name = PR_GetEnv("DISPLAY");
4753 if (!display_name) {
4754 PR_fprintf(PR_STDERR,
4755 "Error: no DISPLAY environment variable specified\n");
4756 return 1;
4760 if (display_name) {
4761 GdkDisplay* disp = gdk_display_open(display_name);
4762 if (!disp) {
4763 PR_fprintf(PR_STDERR, "Error: cannot open display: %s\n", display_name);
4764 return 1;
4766 if (saveDisplayArg) {
4767 if (GdkIsX11Display(disp)) {
4768 SaveWordToEnv("DISPLAY", nsDependentCString(display_name));
4769 } else if (GdkIsWaylandDisplay(disp)) {
4770 SaveWordToEnv("WAYLAND_DISPLAY", nsDependentCString(display_name));
4773 } else {
4774 gdk_display_manager_open_display(gdk_display_manager_get(), nullptr);
4776 # if defined(MOZ_WAYLAND)
4777 // We want to use proxy for main connection only so
4778 // restore original Wayland display for next potential Wayland connections
4779 // from gfx probe code and so on.
4780 if (gWaylandProxy) {
4781 gWaylandProxy->RestoreWaylandDisplay();
4783 if (waylandEnabled && PR_GetEnv("WAYLAND_DISPLAY") && GdkIsX11Display()) {
4784 // Gtk somehow switched to X11 display but we want Wayland.
4785 // It may happen if compositor response is missig or it's slow
4786 // or WAYLAND_DISPLAY is wrong. In such case throw warning but
4787 // run with X11.
4788 Output(true,
4789 "Error: Failed to open Wayland display, fallback to X11. "
4790 "WAYLAND_DISPLAY='%s' DISPLAY='%s'\n",
4791 PR_GetEnv("WAYLAND_DISPLAY"), PR_GetEnv("DISPLAY"));
4793 // We need to unset WAYLAND_DISPLAY. Gfx probe code doesn't have fallback
4794 // to X11 and we'll end with Browser running SW rendering only then.
4795 g_unsetenv("WAYLAND_DISPLAY");
4796 gWaylandProxy = nullptr;
4798 # endif
4799 if (!gdk_display_get_default()) {
4800 Output(true,
4801 "Error: we don't have any display, WAYLAND_DISPLAY='%s' "
4802 "DISPLAY='%s'\n",
4803 PR_GetEnv("WAYLAND_DISPLAY"), PR_GetEnv("DISPLAY"));
4804 return 1;
4806 // Check that Wayland only and X11 only builds
4807 // use appropriate displays.
4808 # if defined(MOZ_WAYLAND) && !defined(MOZ_X11)
4809 if (!GdkIsWaylandDisplay()) {
4810 Output(true, "Wayland only build is missig Wayland display!\n");
4811 return 1;
4813 # endif
4814 # if !defined(MOZ_WAYLAND) && defined(MOZ_X11)
4815 if (!GdkIsX11Display()) {
4816 Output(true, "X11 only build is missig X11 display!\n");
4817 return 1;
4819 # endif
4821 #endif
4822 #if defined(MOZ_HAS_REMOTE)
4823 // handle --remote now that xpcom is fired up
4824 mRemoteService = new nsRemoteService(gAppData->remotingName);
4825 if (mRemoteService && !mDisableRemoteServer) {
4826 mRemoteService->LockStartup();
4827 gRemoteService = mRemoteService;
4829 #endif
4830 #if defined(MOZ_WIDGET_GTK)
4831 g_set_application_name(mAppData->name);
4833 #endif /* defined(MOZ_WIDGET_GTK) */
4834 #ifdef MOZ_X11
4835 // Do this after initializing GDK, or GDK will install its own handler.
4836 XRE_InstallX11ErrorHandler();
4837 #endif
4839 // Call the code to install our handler
4840 #ifdef MOZ_JPROF
4841 setupProfilingStuff();
4842 #endif
4844 bool canRun = false;
4845 rv = mNativeApp->Start(&canRun);
4846 if (NS_FAILED(rv) || !canRun) {
4847 return 1;
4850 #ifdef MOZ_WIDGET_GTK
4851 // startup token might be cleared now, we recover it in case we need a
4852 // restart.
4853 if (!mDesktopStartupID.IsEmpty()) {
4854 // Leak it with extreme prejudice!
4855 PR_SetEnv(ToNewCString("DESKTOP_STARTUP_ID="_ns + mDesktopStartupID));
4858 if (!mXDGActivationToken.IsEmpty()) {
4859 // Leak it with extreme prejudice!
4860 PR_SetEnv(ToNewCString("XDG_ACTIVATION_TOKEN="_ns + mXDGActivationToken));
4862 #endif
4864 // Support exiting early for testing startup sequence. Bug 1360493
4865 if (CheckArg("test-launch-without-hang")) {
4866 *aExitFlag = true;
4867 return 0;
4870 mProfileSvc = NS_GetToolkitProfileService();
4871 if (!mProfileSvc) {
4872 // We failed to choose or create profile - notify user and quit
4873 ProfileMissingDialog(mNativeApp);
4874 return 1;
4877 bool wasDefaultSelection;
4878 nsCOMPtr<nsIToolkitProfile> profile;
4879 rv = SelectProfile(mProfileSvc, mNativeApp, getter_AddRefs(mProfD),
4880 getter_AddRefs(mProfLD), getter_AddRefs(profile),
4881 &wasDefaultSelection);
4882 if (rv == NS_ERROR_LAUNCHED_CHILD_PROCESS || rv == NS_ERROR_ABORT) {
4883 *aExitFlag = true;
4884 return 0;
4887 if (NS_FAILED(rv)) {
4888 // We failed to choose or create profile - notify user and quit
4889 ProfileMissingDialog(mNativeApp);
4890 return 1;
4893 #if defined(MOZ_HAS_REMOTE)
4894 if (mRemoteService) {
4895 // We want a unique profile name to identify the remote instance.
4896 nsCString profileName;
4897 if (profile) {
4898 rv = profile->GetName(profileName);
4900 if (!profile || NS_FAILED(rv) || profileName.IsEmpty()) {
4901 // Couldn't get a name from the profile. Use the directory name?
4902 nsString leafName;
4903 rv = mProfD->GetLeafName(leafName);
4904 if (NS_SUCCEEDED(rv)) {
4905 CopyUTF16toUTF8(leafName, profileName);
4909 mRemoteService->SetProfile(profileName);
4911 if (!mDisableRemoteClient) {
4912 // Try to remote the entire command line. If this fails, start up
4913 // normally.
4914 # ifdef MOZ_WIDGET_GTK
4915 const auto& startupToken =
4916 GdkIsWaylandDisplay() ? mXDGActivationToken : mDesktopStartupID;
4917 # else
4918 const nsCString startupToken;
4919 # endif
4920 RemoteResult rr = mRemoteService->StartClient(
4921 startupToken.IsEmpty() ? nullptr : startupToken.get());
4922 if (rr == REMOTE_FOUND) {
4923 *aExitFlag = true;
4924 mRemoteService->UnlockStartup();
4925 return 0;
4927 if (rr == REMOTE_ARG_BAD) {
4928 mRemoteService->UnlockStartup();
4929 return 1;
4933 #endif
4935 #if defined(MOZ_UPDATER) && !defined(MOZ_WIDGET_ANDROID)
4936 # ifdef XP_WIN
4938 // When automatically restarting for a staged background update
4939 // we want the child process to wait here so that the updater
4940 // does not register two instances running and use that as a
4941 // reason to not process updates. This function requires having
4942 // -restart-pid <param> in the command line to function properly.
4943 // Ensure we keep -restart-pid if we are running tests
4944 if (ARG_FOUND == CheckArgExists("restart-pid") &&
4945 !CheckArg("test-only-automatic-restart-no-wait")) {
4946 // We're not testing and can safely remove it now and read the pid.
4947 const char* restartPidString = nullptr;
4948 CheckArg("restart-pid", &restartPidString, CheckArgFlag::RemoveArg);
4949 // pid should be first parameter following -restart-pid.
4950 uint32_t pid = nsDependentCString(restartPidString).ToInteger(&rv, 10U);
4951 if (NS_SUCCEEDED(rv) && pid > 0) {
4952 printf_stderr(
4953 "*** MaybeWaitForProcessExit: launched pidDWORD = %u ***\n", pid);
4954 RefPtr<nsUpdateProcessor> updater = new nsUpdateProcessor();
4955 if (NS_FAILED(
4956 updater->WaitForProcessExit(pid, MAYBE_WAIT_TIMEOUT_MS))) {
4957 NS_WARNING("Failed to MaybeWaitForProcessExit.");
4959 } else {
4960 NS_WARNING("Failed to parse pid from -restart-pid.");
4964 # endif
4965 Maybe<ShouldNotProcessUpdatesReason> shouldNotProcessUpdatesReason =
4966 ShouldNotProcessUpdates(mDirProvider);
4967 if (shouldNotProcessUpdatesReason.isNothing()) {
4968 // Check for and process any available updates
4969 nsCOMPtr<nsIFile> updRoot;
4970 bool persistent;
4971 rv = mDirProvider.GetFile(XRE_UPDATE_ROOT_DIR, &persistent,
4972 getter_AddRefs(updRoot));
4973 // XRE_UPDATE_ROOT_DIR may fail. Fallback to appDir if failed
4974 if (NS_FAILED(rv)) {
4975 updRoot = mDirProvider.GetAppDir();
4978 // If the MOZ_TEST_PROCESS_UPDATES environment variable already exists, then
4979 // we are being called from the callback application.
4980 if (EnvHasValue("MOZ_TEST_PROCESS_UPDATES")) {
4981 // If the caller has asked us to log our arguments, do so. This is used
4982 // to make sure that the maintenance service successfully launches the
4983 // callback application.
4984 const char* logFile = nullptr;
4985 if (ARG_FOUND == CheckArg("dump-args", &logFile)) {
4986 FILE* logFP = fopen(logFile, "wb");
4987 if (logFP) {
4988 for (int i = 1; i < gRestartArgc; ++i) {
4989 fprintf(logFP, "%s\n", gRestartArgv[i]);
4991 fclose(logFP);
4994 *aExitFlag = true;
4995 return 0;
4998 // Support for processing an update and exiting. The
4999 // MOZ_TEST_PROCESS_UPDATES environment variable will be part of the
5000 // updater's environment and the application that is relaunched by the
5001 // updater. When the application is relaunched by the updater it will be
5002 // removed below and the application will exit.
5003 if (CheckArg("test-process-updates")) {
5004 SaveToEnv("MOZ_TEST_PROCESS_UPDATES=1");
5006 nsCOMPtr<nsIFile> exeFile, exeDir;
5007 rv = mDirProvider.GetFile(XRE_EXECUTABLE_FILE, &persistent,
5008 getter_AddRefs(exeFile));
5009 NS_ENSURE_SUCCESS(rv, 1);
5010 rv = exeFile->GetParent(getter_AddRefs(exeDir));
5011 NS_ENSURE_SUCCESS(rv, 1);
5012 ProcessUpdates(mDirProvider.GetGREDir(), exeDir, updRoot, gRestartArgc,
5013 gRestartArgv, mAppData->version);
5014 if (EnvHasValue("MOZ_TEST_PROCESS_UPDATES")) {
5015 SaveToEnv("MOZ_TEST_PROCESS_UPDATES=");
5016 *aExitFlag = true;
5017 return 0;
5019 } else {
5020 if (CheckArg("test-process-updates") ||
5021 EnvHasValue("MOZ_TEST_PROCESS_UPDATES")) {
5022 // Support for testing *not* processing an update. The launched process
5023 // can witness this environment variable and conclude that its runtime
5024 // environment resulted in not processing updates.
5026 SaveToEnv(nsPrintfCString(
5027 "MOZ_TEST_PROCESS_UPDATES=ShouldNotProcessUpdates(): %s",
5028 ShouldNotProcessUpdatesReasonAsString(
5029 shouldNotProcessUpdatesReason.value()))
5030 .get());
5033 #endif
5035 // We now know there is no existing instance using the selected profile. If
5036 // the profile wasn't selected by specific command line arguments and the
5037 // user has chosen to show the profile manager on startup then do that.
5038 if (wasDefaultSelection) {
5039 bool useSelectedProfile;
5040 rv = mProfileSvc->GetStartWithLastProfile(&useSelectedProfile);
5041 NS_ENSURE_SUCCESS(rv, 1);
5043 if (!useSelectedProfile) {
5044 rv = ShowProfileManager(mProfileSvc, mNativeApp);
5045 if (rv == NS_ERROR_LAUNCHED_CHILD_PROCESS || rv == NS_ERROR_ABORT) {
5046 *aExitFlag = true;
5047 return 0;
5049 if (NS_FAILED(rv)) {
5050 return 1;
5055 // We always want to lock the profile even if we're actually going to reset
5056 // it later.
5057 rv = LockProfile(mNativeApp, mProfD, mProfLD, profile,
5058 getter_AddRefs(mProfileLock));
5059 if (rv == NS_ERROR_LAUNCHED_CHILD_PROCESS || rv == NS_ERROR_ABORT) {
5060 *aExitFlag = true;
5061 return 0;
5062 } else if (NS_FAILED(rv)) {
5063 return 1;
5066 if (gDoProfileReset) {
5067 if (EnvHasValue("MOZ_RESET_PROFILE_RESTART")) {
5068 SaveToEnv("MOZ_RESET_PROFILE_RESTART=");
5069 // We only want to restore the previous session if the profile refresh was
5070 // triggered by user. And if it was a user-triggered profile refresh
5071 // through, say, the safeMode dialog or the troubleshooting page, the
5072 // MOZ_RESET_PROFILE_RESTART env variable would be set. Hence we set
5073 // MOZ_RESET_PROFILE_MIGRATE_SESSION here so that Firefox profile migrator
5074 // would migrate old session data later.
5075 SaveToEnv("MOZ_RESET_PROFILE_MIGRATE_SESSION=1");
5077 // Unlock the source profile.
5078 mProfileLock->Unlock();
5080 // If we're resetting a profile, create a new one and use it to startup.
5081 gResetOldProfile = profile;
5082 rv = mProfileSvc->CreateResetProfile(getter_AddRefs(profile));
5083 if (NS_SUCCEEDED(rv)) {
5084 rv = profile->GetRootDir(getter_AddRefs(mProfD));
5085 NS_ENSURE_SUCCESS(rv, 1);
5086 SaveFileToEnv("XRE_PROFILE_PATH", mProfD);
5088 rv = profile->GetLocalDir(getter_AddRefs(mProfLD));
5089 NS_ENSURE_SUCCESS(rv, 1);
5090 SaveFileToEnv("XRE_PROFILE_LOCAL_PATH", mProfLD);
5092 // Lock the new profile
5093 rv = LockProfile(mNativeApp, mProfD, mProfLD, profile,
5094 getter_AddRefs(mProfileLock));
5095 if (rv == NS_ERROR_LAUNCHED_CHILD_PROCESS || rv == NS_ERROR_ABORT) {
5096 *aExitFlag = true;
5097 return 0;
5098 } else if (NS_FAILED(rv)) {
5099 return 1;
5101 } else {
5102 NS_WARNING("Profile reset failed.");
5103 return 1;
5107 gProfileLock = mProfileLock;
5109 nsAutoCString version;
5110 BuildVersion(version);
5112 #ifdef TARGET_OS_ABI
5113 constexpr auto osABI = nsLiteralCString{TARGET_OS_ABI};
5114 #else
5115 // No TARGET_XPCOM_ABI, but at least the OS is known
5116 constexpr auto osABI = nsLiteralCString{OS_TARGET "_UNKNOWN"};
5117 #endif
5119 // Check for version compatibility with the last version of the app this
5120 // profile was started with. The format of the version stamp is defined
5121 // by the BuildVersion function.
5122 // Also check to see if something has happened to invalidate our
5123 // fastload caches, like an app upgrade.
5125 // If we see .purgecaches, that means someone did a make.
5126 // Re-register components to catch potential changes.
5127 nsCOMPtr<nsIFile> flagFile;
5128 if (mAppData->directory) {
5129 Unused << mAppData->directory->Clone(getter_AddRefs(flagFile));
5131 if (flagFile) {
5132 flagFile->AppendNative(FILE_INVALIDATE_CACHES);
5135 bool cachesOK;
5136 bool isDowngrade;
5137 nsCString lastVersion;
5138 bool versionOK = CheckCompatibility(
5139 mProfD, version, osABI, mDirProvider.GetGREDir(), mAppData->directory,
5140 flagFile, &cachesOK, &isDowngrade, lastVersion);
5142 MOZ_RELEASE_ASSERT(!cachesOK || lastVersion.Equals(version),
5143 "Caches cannot be good if the version has changed.");
5145 #ifdef MOZ_BLOCK_PROFILE_DOWNGRADE
5146 // The argument check must come first so the argument is always removed from
5147 // the command line regardless of whether this is a downgrade or not.
5148 if (!CheckArg("allow-downgrade") && isDowngrade &&
5149 !EnvHasValue("MOZ_ALLOW_DOWNGRADE")) {
5150 rv = CheckDowngrade(mProfD, mNativeApp, mProfileSvc, lastVersion);
5151 if (rv == NS_ERROR_LAUNCHED_CHILD_PROCESS || rv == NS_ERROR_ABORT) {
5152 *aExitFlag = true;
5153 return 0;
5156 #endif
5158 rv = mDirProvider.SetProfile(mProfD, mProfLD);
5159 NS_ENSURE_SUCCESS(rv, 1);
5161 //////////////////////// NOW WE HAVE A PROFILE ////////////////////////
5163 mozilla::Telemetry::SetProfileDir(mProfD);
5165 if (mAppData->flags & NS_XRE_ENABLE_CRASH_REPORTER) {
5166 MakeOrSetMinidumpPath(mProfD);
5169 CrashReporter::SetProfileDirectory(mProfD);
5171 #ifdef MOZ_ASAN_REPORTER
5172 // In ASan reporter builds, we need to set ASan's log_path as early as
5173 // possible, so it dumps its errors into files there instead of using
5174 // the default stderr location. Since this is crucial for ASan reporter
5175 // to work at all (and we don't want people to use a non-functional
5176 // ASan reporter build), all failures while setting log_path are fatal.
5177 setASanReporterPath(mProfD);
5179 // Export to env for child processes
5180 SaveFileToEnv("ASAN_REPORTER_PATH", mProfD);
5181 #endif
5183 bool lastStartupWasCrash = CheckLastStartupWasCrash();
5185 CrashReporter::RecordAnnotationBool(
5186 CrashReporter::Annotation::LastStartupWasCrash, lastStartupWasCrash);
5188 if (CheckArg("purgecaches") || PR_GetEnv("MOZ_PURGE_CACHES") ||
5189 lastStartupWasCrash || gSafeMode) {
5190 cachesOK = false;
5193 CrashReporter::RecordAnnotationBool(
5194 CrashReporter::Annotation::StartupCacheValid, cachesOK && versionOK);
5196 // Every time a profile is loaded by a build with a different version,
5197 // it updates the compatibility.ini file saying what version last wrote
5198 // the fastload caches. On subsequent launches if the version matches,
5199 // there is no need for re-registration. If the user loads the same
5200 // profile in different builds the component registry must be
5201 // re-generated to prevent mysterious component loading failures.
5203 bool startupCacheValid = true;
5205 if (!cachesOK || !versionOK) {
5206 QuotaManager::InvalidateQuotaCache();
5208 startupCacheValid = RemoveComponentRegistries(mProfD, mProfLD, false);
5210 // Rewrite compatibility.ini to match the current build. The next run
5211 // should attempt to invalidate the caches if either this run is safe mode
5212 // or the attempt to invalidate the caches this time failed.
5213 WriteVersion(mProfD, version, osABI, mDirProvider.GetGREDir(),
5214 mAppData->directory, gSafeMode || !startupCacheValid);
5217 if (!startupCacheValid) StartupCache::IgnoreDiskCache();
5219 if (flagFile) {
5220 flagFile->Remove(true);
5223 // Flush any pending page load events.
5224 mozilla::glean_pings::Pageload.Submit("startup"_ns);
5226 if (!isBackgroundTaskMode) {
5227 #ifdef USE_GLX_TEST
5228 GfxInfo::FireGLXTestProcess();
5229 #endif
5230 #ifdef MOZ_WAYLAND
5231 // Make sure we have wayland connection for main thread.
5232 // It's used as template to create display connections
5233 // for different threads.
5234 if (IsWaylandEnabled()) {
5235 MOZ_UNUSED(WaylandDisplayGet());
5237 #endif
5238 #ifdef MOZ_WIDGET_GTK
5239 nsAppShell::InstallTermSignalHandler();
5240 #endif
5243 return 0;
5246 #if defined(MOZ_SANDBOX)
5247 void AddSandboxAnnotations() {
5248 CrashReporter::RecordAnnotationU32(
5249 CrashReporter::Annotation::ContentSandboxLevel,
5250 GetEffectiveContentSandboxLevel());
5251 CrashReporter::RecordAnnotationU32(CrashReporter::Annotation::GpuSandboxLevel,
5252 GetEffectiveGpuSandboxLevel());
5254 // Include whether or not this instance is capable of content sandboxing
5255 bool sSandboxCapable = false;
5257 # if defined(XP_WIN)
5258 // All supported Windows versions support some level of content sandboxing
5259 sSandboxCapable = true;
5260 # elif defined(XP_MACOSX)
5261 // All supported OS X versions are capable
5262 sSandboxCapable = true;
5263 # elif defined(XP_LINUX)
5264 sSandboxCapable = SandboxInfo::Get().CanSandboxContent();
5265 # elif defined(__OpenBSD__)
5266 sSandboxCapable = true;
5267 StartOpenBSDSandbox(GeckoProcessType_Default);
5268 # endif
5270 CrashReporter::RecordAnnotationBool(
5271 CrashReporter::Annotation::ContentSandboxCapable, sSandboxCapable);
5273 #endif /* MOZ_SANDBOX */
5276 * XRE_mainRun - Command line startup, profile migration, and
5277 * the calling of appStartup->Run().
5279 nsresult XREMain::XRE_mainRun() {
5280 nsresult rv = NS_OK;
5281 NS_ASSERTION(mScopedXPCOM, "Scoped xpcom not initialized.");
5283 #if defined(XP_WIN)
5284 RefPtr<mozilla::DllServices> dllServices(mozilla::DllServices::Get());
5285 dllServices->StartUntrustedModulesProcessor(false);
5286 auto dllServicesDisable =
5287 MakeScopeExit([&dllServices]() { dllServices->DisableFull(); });
5289 mozilla::mscom::InitProfilerMarkers();
5290 #endif // defined(XP_WIN)
5292 // We need the appStartup pointer to span multiple scopes, so we declare
5293 // it here.
5294 nsCOMPtr<nsIAppStartup> appStartup;
5295 // Ditto with the command line.
5296 nsCOMPtr<nsICommandLineRunner> cmdLine;
5299 #ifdef XP_MACOSX
5300 // In this scope, create an autorelease pool that will leave scope with
5301 // it just before entering our event loop.
5302 mozilla::MacAutoreleasePool pool;
5303 #endif
5305 rv = mScopedXPCOM->SetWindowCreator(mNativeApp);
5306 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
5308 // tell the crash reporter to also send the release channel
5309 nsCOMPtr<nsIPrefService> prefs =
5310 do_GetService("@mozilla.org/preferences-service;1", &rv);
5311 if (NS_SUCCEEDED(rv)) {
5312 nsCOMPtr<nsIPrefBranch> defaultPrefBranch;
5313 rv = prefs->GetDefaultBranch(nullptr, getter_AddRefs(defaultPrefBranch));
5315 if (NS_SUCCEEDED(rv)) {
5316 nsAutoCString sval;
5317 rv = defaultPrefBranch->GetCharPref("app.update.channel", sval);
5318 if (NS_SUCCEEDED(rv)) {
5319 CrashReporter::RecordAnnotationNSCString(
5320 CrashReporter::Annotation::ReleaseChannel, sval);
5324 // Needs to be set after xpcom initialization.
5325 bool includeContextHeap = Preferences::GetBool(
5326 "toolkit.crashreporter.include_context_heap", false);
5327 CrashReporter::SetIncludeContextHeap(includeContextHeap);
5329 #if defined(XP_LINUX) && !defined(ANDROID)
5330 PR_CreateThread(PR_USER_THREAD, AnnotateLSBRelease, 0, PR_PRIORITY_LOW,
5331 PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD, 0);
5332 #endif
5334 if (mStartOffline) {
5335 nsCOMPtr<nsIIOService> io(
5336 do_GetService("@mozilla.org/network/io-service;1"));
5337 NS_ENSURE_TRUE(io, NS_ERROR_FAILURE);
5338 io->SetManageOfflineStatus(false);
5339 io->SetOffline(true);
5342 #ifdef XP_WIN
5343 mozilla::DllPrefetchExperimentRegistryInfo prefetchRegInfo;
5344 mozilla::AlteredDllPrefetchMode dllPrefetchMode =
5345 prefetchRegInfo.GetAlteredDllPrefetchMode();
5347 if (!PR_GetEnv("XRE_NO_DLL_READAHEAD") &&
5348 dllPrefetchMode != mozilla::AlteredDllPrefetchMode::NoPrefetch) {
5349 nsCOMPtr<nsIFile> greDir = mDirProvider.GetGREDir();
5350 nsAutoString path;
5351 rv = greDir->GetPath(path);
5352 if (NS_SUCCEEDED(rv)) {
5353 PRThread* readAheadThread;
5354 wchar_t* pathRaw;
5356 // We use the presence of a path argument inside the thread to determine
5357 // which list of Dlls to use. The old list does not need access to the
5358 // GRE dir, so the path argument is set to a null pointer.
5359 if (dllPrefetchMode ==
5360 mozilla::AlteredDllPrefetchMode::OptimizedPrefetch) {
5361 pathRaw = new wchar_t[MAX_PATH];
5362 wcscpy_s(pathRaw, MAX_PATH, path.get());
5363 } else {
5364 pathRaw = nullptr;
5366 readAheadThread = PR_CreateThread(
5367 PR_USER_THREAD, ReadAheadDlls_ThreadStart, (void*)pathRaw,
5368 PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD, 0);
5369 if (readAheadThread == NULL) {
5370 delete[] pathRaw;
5374 #endif
5376 if (gDoMigration) {
5377 nsCOMPtr<nsIFile> file;
5378 mDirProvider.GetAppDir()->Clone(getter_AddRefs(file));
5379 file->AppendNative("override.ini"_ns);
5380 nsINIParser parser;
5381 nsresult rv = parser.Init(file);
5382 // if override.ini doesn't exist, also check for distribution.ini
5383 if (NS_FAILED(rv)) {
5384 bool persistent;
5385 mDirProvider.GetFile(XRE_APP_DISTRIBUTION_DIR, &persistent,
5386 getter_AddRefs(file));
5387 file->AppendNative("distribution.ini"_ns);
5388 rv = parser.Init(file);
5390 if (NS_SUCCEEDED(rv)) {
5391 nsAutoCString buf;
5392 rv = parser.GetString("XRE", "EnableProfileMigrator", buf);
5393 if (NS_SUCCEEDED(rv)) {
5394 if (buf[0] == '0' || buf[0] == 'f' || buf[0] == 'F') {
5395 gDoMigration = false;
5401 // We'd like to initialize the JSContext *after* reading the user prefs.
5402 // Unfortunately that's not possible if we have to do profile migration
5403 // because that requires us to execute JS before reading user prefs.
5404 // Restarting the browser after profile migration would fix this. See
5405 // bug 1592523.
5406 bool initializedJSContext = false;
5409 // Profile Migration
5410 if (mAppData->flags & NS_XRE_ENABLE_PROFILE_MIGRATOR && gDoMigration) {
5411 gDoMigration = false;
5413 xpc::InitializeJSContext();
5414 initializedJSContext = true;
5416 nsCOMPtr<nsIProfileMigrator> pm(
5417 do_CreateInstance(NS_PROFILEMIGRATOR_CONTRACTID));
5418 if (pm) {
5419 nsAutoCString aKey;
5420 nsAutoCString aName;
5421 if (gDoProfileReset) {
5422 // Automatically migrate from the current application if we just
5423 // reset the profile.
5424 aKey = MOZ_APP_NAME;
5425 gResetOldProfile->GetName(aName);
5427 #ifdef XP_MACOSX
5428 // Necessary for migration wizard to be accessible.
5429 InitializeMacApp();
5430 #endif
5431 pm->Migrate(&mDirProvider, aKey, aName);
5435 if (gDoProfileReset) {
5436 if (!initializedJSContext) {
5437 xpc::InitializeJSContext();
5438 initializedJSContext = true;
5441 nsresult backupCreated =
5442 ProfileResetCleanup(mProfileSvc, gResetOldProfile);
5443 if (NS_FAILED(backupCreated)) {
5444 NS_WARNING("Could not cleanup the profile that was reset");
5449 // Initialize user preferences before notifying startup observers so they're
5450 // ready in time for early consumers, such as the component loader.
5451 mDirProvider.InitializeUserPrefs();
5453 // Now that all (user) prefs have been loaded we can initialize the main
5454 // thread's JSContext.
5455 if (!initializedJSContext) {
5456 xpc::InitializeJSContext();
5459 // Finally, now that JS has been initialized, we can finish pref loading.
5460 // This needs to happen after JS and XPConnect initialization because
5461 // AutoConfig files require JS execution. Note that this means AutoConfig
5462 // files can't override JS engine start-up prefs.
5463 mDirProvider.FinishInitializingUserPrefs();
5465 #if defined(MOZ_SANDBOX) && defined(XP_WIN)
5466 // Now that we have preferences and the directory provider, we can
5467 // finish initializing SandboxBroker. This must happen before the GFX
5468 // platform is initialized (which will launch the GPU process), which
5469 // occurs when the "app-startup" category is started up below
5471 // After this completes, we are ready to launch sandboxed processes
5472 mozilla::SandboxBroker::GeckoDependentInitialize();
5473 #endif
5475 nsCOMPtr<nsIFile> workingDir;
5476 rv = NS_GetSpecialDirectory(NS_OS_CURRENT_WORKING_DIR,
5477 getter_AddRefs(workingDir));
5478 if (NS_FAILED(rv)) {
5479 // No working dir? This can happen if it gets deleted before we start.
5480 workingDir = nullptr;
5483 cmdLine = new nsCommandLine();
5485 rv = cmdLine->Init(gArgc, gArgv, workingDir,
5486 nsICommandLine::STATE_INITIAL_LAUNCH);
5487 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
5489 // "app-startup" is the name of both the category and the event
5490 NS_CreateServicesFromCategory("app-startup", cmdLine, "app-startup",
5491 nullptr);
5493 appStartup = components::AppStartup::Service();
5494 NS_ENSURE_TRUE(appStartup, NS_ERROR_FAILURE);
5496 mDirProvider.DoStartup();
5498 #ifdef XP_WIN
5499 // It needs to be called on the main thread because it has to use
5500 // nsObserverService.
5501 EnsureWin32kInitialized();
5502 #endif
5504 // As FilePreferences need the profile directory, we must initialize right
5505 // here.
5506 mozilla::FilePreferences::InitDirectoriesAllowlist();
5507 mozilla::FilePreferences::InitPrefs();
5509 nsCString userAgentLocale;
5510 LocaleService::GetInstance()->GetAppLocaleAsBCP47(userAgentLocale);
5511 CrashReporter::RecordAnnotationNSCString(
5512 CrashReporter::Annotation::useragent_locale, userAgentLocale);
5514 if (!AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed)) {
5515 /* Special-case services that need early access to the command
5516 line. */
5517 nsCOMPtr<nsIObserverService> obsService =
5518 mozilla::services::GetObserverService();
5519 if (obsService) {
5520 obsService->NotifyObservers(cmdLine, "command-line-startup", nullptr);
5524 #ifdef XP_WIN
5525 // Hack to sync up the various environment storages. XUL_APP_FILE is special
5526 // in that it comes from a different CRT (firefox.exe's static-linked copy).
5527 // Ugly details in http://bugzil.la/1175039#c27
5528 char appFile[MAX_PATH];
5529 if (GetEnvironmentVariableA("XUL_APP_FILE", appFile, sizeof(appFile))) {
5530 SmprintfPointer saved = mozilla::Smprintf("XUL_APP_FILE=%s", appFile);
5531 // We intentionally leak the string here since it is required by
5532 // PR_SetEnv.
5533 PR_SetEnv(saved.release());
5535 #endif
5537 mozilla::AppShutdown::SaveEnvVarsForPotentialRestart();
5539 // clear out any environment variables which may have been set
5540 // during the relaunch process now that we know we won't be relaunching.
5541 SaveToEnv("XRE_PROFILE_PATH=");
5542 SaveToEnv("XRE_PROFILE_LOCAL_PATH=");
5543 SaveToEnv("XRE_START_OFFLINE=");
5544 SaveToEnv("XUL_APP_FILE=");
5545 SaveToEnv("XRE_BINARY_PATH=");
5546 SaveToEnv("XRE_RESTARTED_BY_PROFILE_MANAGER=");
5548 if (!AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed)) {
5549 // Don't create the hidden window during startup on
5550 // platforms that don't always need it.
5551 #ifdef XP_MACOSX
5552 bool lazyHiddenWindow = false;
5553 #else
5554 bool lazyHiddenWindow = true;
5555 #endif
5557 #ifdef MOZ_BACKGROUNDTASKS
5558 if (BackgroundTasks::IsBackgroundTaskMode()) {
5559 // Background tasks aren't going to load a chrome XUL document.
5560 lazyHiddenWindow = true;
5562 #endif
5564 if (!lazyHiddenWindow) {
5565 rv = appStartup->CreateHiddenWindow();
5566 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
5569 #ifdef XP_WIN
5570 Preferences::RegisterCallbackAndCall(
5571 RegisterApplicationRestartChanged,
5572 PREF_WIN_REGISTER_APPLICATION_RESTART);
5573 SetupAlteredPrefetchPref();
5574 SetupSkeletonUIPrefs();
5575 # if defined(MOZ_LAUNCHER_PROCESS)
5576 SetupLauncherProcessPref();
5577 # endif // defined(MOZ_LAUNCHER_PROCESS)
5578 # if defined(MOZ_DEFAULT_BROWSER_AGENT)
5579 # if defined(MOZ_BACKGROUNDTASKS)
5580 // The backgroundtask profile is not a browsing profile, let alone the new
5581 // default profile, so don't mirror its properties into the registry.
5582 if (!BackgroundTasks::IsBackgroundTaskMode())
5583 # endif // defined(MOZ_BACKGROUNDTASKS)
5585 Preferences::RegisterCallbackAndCall(
5586 &OnDefaultAgentTelemetryPrefChanged,
5587 kPrefHealthReportUploadEnabled);
5588 Preferences::RegisterCallbackAndCall(
5589 &OnDefaultAgentTelemetryPrefChanged, kPrefDefaultAgentEnabled);
5591 Preferences::RegisterCallbackAndCall(
5592 &OnDefaultAgentRemoteSettingsPrefChanged,
5593 kPrefServicesSettingsServer);
5595 Preferences::RegisterCallbackAndCall(
5596 &OnSetDefaultBrowserUserChoicePrefChanged,
5597 kPrefSetDefaultBrowserUserChoicePref);
5599 SetDefaultAgentLastRunTime();
5601 # endif // defined(MOZ_DEFAULT_BROWSER_AGENT)
5602 #endif
5604 #if defined(MOZ_WIDGET_GTK)
5605 // Clear the environment variables so they won't be inherited by child
5606 // processes and confuse things.
5607 for (const auto& name : kStartupTokenNames) {
5608 g_unsetenv(name.get());
5610 #endif
5612 #ifdef XP_MACOSX
5613 InitializeMacApp();
5615 // we re-initialize the command-line service and do appleevents munging
5616 // after we are sure that we're not restarting
5617 cmdLine = new nsCommandLine();
5619 char** tempArgv = static_cast<char**>(malloc(gArgc * sizeof(char*)));
5620 for (int i = 0; i < gArgc; i++) {
5621 tempArgv[i] = strdup(gArgv[i]);
5623 CommandLineServiceMac::SetupMacCommandLine(gArgc, tempArgv, false);
5624 rv = cmdLine->Init(gArgc, tempArgv, workingDir,
5625 nsICommandLine::STATE_INITIAL_LAUNCH);
5626 free(tempArgv);
5627 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
5629 # ifdef MOZILLA_OFFICIAL
5630 // Check if we're running from a DMG or an app translocated location and
5631 // allow the user to install to the Applications directory.
5632 if (MacRunFromDmgUtils::MaybeInstallAndRelaunch()) {
5633 bool userAllowedQuit = true;
5634 appStartup->Quit(nsIAppStartup::eForceQuit, 0, &userAllowedQuit);
5636 # endif
5637 #endif
5639 nsCOMPtr<nsIObserverService> obsService =
5640 mozilla::services::GetObserverService();
5641 if (obsService)
5642 obsService->NotifyObservers(nullptr, "final-ui-startup", nullptr);
5644 (void)appStartup->DoneStartingUp();
5646 CrashReporter::RecordAnnotationBool(
5647 CrashReporter::Annotation::StartupCrash, false);
5649 AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed);
5652 if (!AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed)) {
5653 rv = cmdLine->Run();
5654 NS_ENSURE_SUCCESS_LOG(rv, NS_ERROR_FAILURE);
5657 if (!AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed)) {
5658 #if defined(MOZ_HAS_REMOTE)
5659 // if we have X remote support, start listening for requests on the
5660 // proxy window.
5661 if (mRemoteService && !mDisableRemoteServer) {
5662 mRemoteService->StartupServer();
5663 mRemoteService->UnlockStartup();
5664 gRemoteService = nullptr;
5666 #endif /* MOZ_WIDGET_GTK */
5668 mNativeApp->Enable();
5671 #ifdef MOZ_INSTRUMENT_EVENT_LOOP
5672 if (PR_GetEnv("MOZ_INSTRUMENT_EVENT_LOOP")) {
5673 bool logToConsole = true;
5674 mozilla::InitEventTracing(logToConsole);
5676 #endif /* MOZ_INSTRUMENT_EVENT_LOOP */
5678 // Send Telemetry about Gecko version and buildid
5679 mozilla::glean::gecko::version.Set(nsDependentCString(gAppData->version));
5680 mozilla::glean::gecko::build_id.Set(nsDependentCString(gAppData->buildID));
5682 #if defined(MOZ_SANDBOX) && defined(XP_LINUX)
5683 // If we're on Linux, we now have information about the OS capabilities
5684 // available to us.
5685 SandboxInfo sandboxInfo = SandboxInfo::Get();
5686 Telemetry::Accumulate(Telemetry::SANDBOX_HAS_SECCOMP_BPF,
5687 sandboxInfo.Test(SandboxInfo::kHasSeccompBPF));
5688 Telemetry::Accumulate(Telemetry::SANDBOX_HAS_SECCOMP_TSYNC,
5689 sandboxInfo.Test(SandboxInfo::kHasSeccompTSync));
5690 Telemetry::Accumulate(
5691 Telemetry::SANDBOX_HAS_USER_NAMESPACES_PRIVILEGED,
5692 sandboxInfo.Test(SandboxInfo::kHasPrivilegedUserNamespaces));
5693 Telemetry::Accumulate(Telemetry::SANDBOX_HAS_USER_NAMESPACES,
5694 sandboxInfo.Test(SandboxInfo::kHasUserNamespaces));
5695 Telemetry::Accumulate(Telemetry::SANDBOX_CONTENT_ENABLED,
5696 sandboxInfo.Test(SandboxInfo::kEnabledForContent));
5697 Telemetry::Accumulate(Telemetry::SANDBOX_MEDIA_ENABLED,
5698 sandboxInfo.Test(SandboxInfo::kEnabledForMedia));
5700 CrashReporter::RecordAnnotationU32(
5701 CrashReporter::Annotation::ContentSandboxCapabilities,
5702 sandboxInfo.AsInteger());
5703 #endif /* MOZ_SANDBOX && XP_LINUX */
5705 #if defined(XP_WIN)
5706 LauncherResult<bool> isAdminWithoutUac = IsAdminWithoutUac();
5707 if (isAdminWithoutUac.isOk()) {
5708 Telemetry::ScalarSet(
5709 Telemetry::ScalarID::OS_ENVIRONMENT_IS_ADMIN_WITHOUT_UAC,
5710 isAdminWithoutUac.unwrap());
5712 #endif /* XP_WIN */
5714 #if defined(MOZ_SANDBOX)
5715 AddSandboxAnnotations();
5716 #endif /* MOZ_SANDBOX */
5718 mProfileSvc->CompleteStartup();
5721 #ifdef MOZ_BACKGROUNDTASKS
5722 if (BackgroundTasks::IsBackgroundTaskMode()) {
5723 // In background task mode, we don't fire various delayed initialization
5724 // notifications, which in the regular browser is how startup crash tracking
5725 // is marked as finished. Here, getting this far means we don't have a
5726 // startup crash.
5727 rv = appStartup->TrackStartupCrashEnd();
5728 NS_ENSURE_SUCCESS(rv, rv);
5730 // We never open a window, but don't want to exit immediately.
5731 rv = appStartup->EnterLastWindowClosingSurvivalArea();
5732 NS_ENSURE_SUCCESS(rv, rv);
5734 // Avoid some small differences in initialization order across platforms.
5735 nsCOMPtr<nsIPowerManagerService> powerManagerService =
5736 do_GetService(POWERMANAGERSERVICE_CONTRACTID);
5737 nsCOMPtr<nsIStringBundleService> stringBundleService =
5738 do_GetService(NS_STRINGBUNDLE_CONTRACTID);
5740 rv = BackgroundTasks::RunBackgroundTask(cmdLine);
5741 NS_ENSURE_SUCCESS(rv, rv);
5743 #endif
5746 rv = appStartup->Run();
5747 if (NS_FAILED(rv)) {
5748 NS_ERROR("failed to run appstartup");
5749 gLogConsoleErrors = true;
5753 return rv;
5756 #if defined(MOZ_WIDGET_ANDROID)
5757 static already_AddRefed<nsIFile> GreOmniPath(int argc, char** argv) {
5758 nsresult rv;
5760 const char* path = nullptr;
5761 ArgResult ar = CheckArg(argc, argv, "greomni", &path, CheckArgFlag::None);
5762 if (ar == ARG_BAD) {
5763 PR_fprintf(PR_STDERR,
5764 "Error: argument --greomni requires a path argument\n");
5765 return nullptr;
5768 if (!path) return nullptr;
5770 nsCOMPtr<nsIFile> greOmni;
5771 rv = XRE_GetFileFromPath(path, getter_AddRefs(greOmni));
5772 if (NS_FAILED(rv)) {
5773 PR_fprintf(PR_STDERR, "Error: argument --greomni requires a valid path\n");
5774 return nullptr;
5777 return greOmni.forget();
5779 #endif
5782 * XRE_main - A class based main entry point used by most platforms.
5783 * Note that on OSX, aAppData->xreDirectory will point to
5784 * .app/Contents/Resources.
5786 int XREMain::XRE_main(int argc, char* argv[], const BootstrapConfig& aConfig) {
5787 gArgc = argc;
5788 gArgv = argv;
5790 ScopedLogging log;
5792 mozilla::LogModule::Init(gArgc, gArgv);
5794 #ifndef XP_LINUX
5795 NS_SetCurrentThreadName("MainThread");
5796 #endif
5798 AUTO_BASE_PROFILER_LABEL("XREMain::XRE_main (around Gecko Profiler)", OTHER);
5799 AUTO_PROFILER_INIT;
5800 AUTO_PROFILER_LABEL("XREMain::XRE_main", OTHER);
5802 #ifdef XP_MACOSX
5803 // We call this early because it will kick off a background-thread task
5804 // to register the fonts, and we'd like it to have a chance to complete
5805 // before gfxPlatform initialization actually requires it.
5806 gfxPlatformMac::RegisterSupplementalFonts();
5807 #endif
5809 #ifdef MOZ_CODE_COVERAGE
5810 CodeCoverageHandler::Init();
5811 #endif
5813 nsresult rv = NS_OK;
5815 if (aConfig.appData) {
5816 mAppData = MakeUnique<XREAppData>(*aConfig.appData);
5817 } else {
5818 MOZ_RELEASE_ASSERT(aConfig.appDataPath);
5819 nsCOMPtr<nsIFile> appini;
5820 rv = XRE_GetFileFromPath(aConfig.appDataPath, getter_AddRefs(appini));
5821 if (NS_FAILED(rv)) {
5822 Output(true, "Error: unrecognized path: %s\n", aConfig.appDataPath);
5823 return 1;
5826 mAppData = MakeUnique<XREAppData>();
5827 rv = XRE_ParseAppData(appini, *mAppData);
5828 if (NS_FAILED(rv)) {
5829 Output(true, "Couldn't read application.ini");
5830 return 1;
5833 appini->GetParent(getter_AddRefs(mAppData->directory));
5836 const char* appRemotingName = getenv("MOZ_APP_REMOTINGNAME");
5837 if (appRemotingName) {
5838 mAppData->remotingName = appRemotingName;
5839 } else if (!mAppData->remotingName) {
5840 mAppData->remotingName = mAppData->name;
5842 // used throughout this file
5843 gAppData = mAppData.get();
5845 nsCOMPtr<nsIFile> binFile;
5846 rv = XRE_GetBinaryPath(getter_AddRefs(binFile));
5847 NS_ENSURE_SUCCESS(rv, 1);
5849 rv = binFile->GetPath(gAbsoluteArgv0Path);
5850 NS_ENSURE_SUCCESS(rv, 1);
5852 if (!mAppData->xreDirectory) {
5853 nsCOMPtr<nsIFile> greDir;
5855 #if defined(MOZ_WIDGET_ANDROID)
5856 greDir = GreOmniPath(argc, argv);
5857 if (!greDir) {
5858 return 2;
5860 #else
5861 rv = binFile->GetParent(getter_AddRefs(greDir));
5862 if (NS_FAILED(rv)) return 2;
5863 #endif
5865 #ifdef XP_MACOSX
5866 nsCOMPtr<nsIFile> parent;
5867 greDir->GetParent(getter_AddRefs(parent));
5868 greDir = parent.forget();
5869 greDir->AppendNative("Resources"_ns);
5870 #endif
5872 mAppData->xreDirectory = greDir;
5875 #if defined(MOZ_WIDGET_ANDROID)
5876 nsCOMPtr<nsIFile> dataDir;
5877 rv = binFile->GetParent(getter_AddRefs(dataDir));
5878 if (NS_FAILED(rv)) return 2;
5880 mAppData->directory = dataDir;
5881 #else
5882 if (aConfig.appData && aConfig.appDataPath) {
5883 mAppData->xreDirectory->Clone(getter_AddRefs(mAppData->directory));
5884 mAppData->directory->AppendNative(nsDependentCString(aConfig.appDataPath));
5886 #endif
5888 if (!mAppData->directory) {
5889 mAppData->directory = mAppData->xreDirectory;
5892 #if defined(XP_WIN)
5893 # if defined(MOZ_SANDBOX)
5894 mAppData->sandboxBrokerServices = aConfig.sandboxBrokerServices;
5895 # endif // defined(MOZ_SANDBOX)
5898 DebugOnly<bool> result = WindowsBCryptInitialization();
5899 MOZ_ASSERT(result);
5902 # if defined(_M_IX86) || defined(_M_X64)
5904 DebugOnly<bool> result = WindowsMsctfInitialization();
5905 MOZ_ASSERT(result);
5907 # endif // _M_IX86 || _M_X64
5909 #endif // defined(XP_WIN)
5911 // Once we unset the exception handler, we lose the ability to properly
5912 // detect hangs -- they show up as crashes. We do this as late as possible.
5913 // In particular, after ProcessRuntime is destroyed on Windows.
5914 auto unsetExceptionHandler = MakeScopeExit([&] {
5915 if (mAppData->flags & NS_XRE_ENABLE_CRASH_REPORTER)
5916 return CrashReporter::UnsetExceptionHandler();
5917 return NS_OK;
5920 mozilla::AutoIOInterposer ioInterposerGuard;
5921 ioInterposerGuard.Init();
5923 #if defined(XP_WIN)
5924 // We should have already done this when we created the skeleton UI. However,
5925 // there is code in here which needs xul in order to work, like EnsureMTA. It
5926 // should be setup that running it again is safe.
5927 mozilla::mscom::ProcessRuntime msCOMRuntime;
5928 #endif
5930 // init
5931 bool exit = false;
5932 int result = XRE_mainInit(&exit);
5933 if (result != 0 || exit) return result;
5935 // If we exit gracefully, remove the startup crash canary file.
5936 auto cleanup = MakeScopeExit([&]() -> nsresult {
5937 if (mProfLD) {
5938 nsCOMPtr<nsIFile> crashFile;
5939 MOZ_TRY_VAR(crashFile, GetIncompleteStartupFile(mProfLD));
5940 crashFile->Remove(false);
5942 return NS_OK;
5945 // startup
5946 result = XRE_mainStartup(&exit);
5947 if (result != 0 || exit) return result;
5949 // Start the real application. We use |aInitJSContext = false| because
5950 // XRE_mainRun wants to initialize the JSContext after reading user prefs.
5952 mScopedXPCOM = MakeUnique<ScopedXPCOMStartup>();
5954 rv = mScopedXPCOM->Initialize(/* aInitJSContext = */ false);
5955 NS_ENSURE_SUCCESS(rv, 1);
5957 // run!
5958 rv = XRE_mainRun();
5960 #ifdef MOZ_X11
5961 XRE_CleanupX11ErrorHandler();
5962 #endif
5964 #ifdef MOZ_INSTRUMENT_EVENT_LOOP
5965 mozilla::ShutdownEventTracing();
5966 #endif
5968 gAbsoluteArgv0Path.Truncate();
5970 #if defined(MOZ_HAS_REMOTE)
5971 // Shut down the remote service. We must do this before calling LaunchChild
5972 // if we're restarting because otherwise the new instance will attempt to
5973 // remote to this instance.
5974 if (mRemoteService && !mDisableRemoteServer) {
5975 mRemoteService->ShutdownServer();
5977 #endif /* MOZ_WIDGET_GTK */
5979 mScopedXPCOM = nullptr;
5981 // unlock the profile after ScopedXPCOMStartup object (xpcom)
5982 // has gone out of scope. see bug #386739 for more details
5983 mProfileLock->Unlock();
5984 gProfileLock = nullptr;
5986 gLastAppVersion.Truncate();
5987 gLastAppBuildID.Truncate();
5989 #ifdef MOZ_WIDGET_GTK
5990 // gdk_display_close also calls gdk_display_manager_set_default_display
5991 // appropriately when necessary.
5992 if (!gfxPlatform::IsHeadless()) {
5993 # ifdef MOZ_WAYLAND
5994 WaylandDisplayRelease();
5995 gWaylandProxy = nullptr;
5996 # endif
5998 #endif
6000 mozilla::AppShutdown::MaybeDoRestart();
6002 XRE_DeinitCommandLine();
6004 if (NS_FAILED(rv)) {
6005 return 1;
6007 return mozilla::AppShutdown::GetExitCode();
6010 void XRE_StopLateWriteChecks(void) { mozilla::StopLateWriteChecks(); }
6012 int XRE_main(int argc, char* argv[], const BootstrapConfig& aConfig) {
6013 XREMain main;
6015 int result = main.XRE_main(argc, argv, aConfig);
6016 mozilla::RecordShutdownEndTimeStamp();
6017 #ifdef MOZ_BACKGROUNDTASKS
6018 // This is well after the profile has been unlocked, so it's okay if this does
6019 // delete this background task's temporary profile.
6020 mozilla::BackgroundTasks::Shutdown();
6021 #endif
6022 return result;
6025 nsresult XRE_InitCommandLine(int aArgc, char* aArgv[]) {
6026 nsresult rv = NS_OK;
6028 #if defined(XP_WIN)
6029 CommandLine::Init(aArgc, aArgv);
6030 #else
6032 // these leak on error, but that's OK: we'll just exit()
6033 char** canonArgs = new char*[aArgc];
6035 // get the canonical version of the binary's path
6036 nsCOMPtr<nsIFile> binFile;
6037 rv = XRE_GetBinaryPath(getter_AddRefs(binFile));
6038 if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
6040 nsAutoCString canonBinPath;
6041 rv = binFile->GetNativePath(canonBinPath);
6042 if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
6044 canonArgs[0] = strdup(canonBinPath.get());
6046 for (int i = 1; i < aArgc; ++i) {
6047 if (aArgv[i]) {
6048 canonArgs[i] = strdup(aArgv[i]);
6052 NS_ASSERTION(!CommandLine::IsInitialized(), "Bad news!");
6053 CommandLine::Init(aArgc, canonArgs);
6055 for (int i = 0; i < aArgc; ++i) free(canonArgs[i]);
6056 delete[] canonArgs;
6057 #endif
6059 #if defined(MOZ_WIDGET_ANDROID)
6060 // gAppData is non-null iff this is the parent process. Otherwise,
6061 // the `-greomni`/`-appomni` flags are cross-platform and handled in
6062 // ContentProcess::Init.
6063 if (gAppData) {
6064 nsCOMPtr<nsIFile> greOmni = gAppData->xreDirectory;
6065 if (!greOmni) {
6066 return NS_ERROR_FAILURE;
6068 mozilla::Omnijar::Init(greOmni, greOmni);
6070 #endif
6072 return rv;
6075 nsresult XRE_DeinitCommandLine() {
6076 nsresult rv = NS_OK;
6078 CommandLine::Terminate();
6080 return rv;
6083 GeckoProcessType XRE_GetProcessType() { return GetGeckoProcessType(); }
6085 const char* XRE_GetProcessTypeString() {
6086 return XRE_GeckoProcessTypeToString(XRE_GetProcessType());
6089 bool XRE_IsE10sParentProcess() {
6090 #ifdef MOZ_WIDGET_ANDROID
6091 return XRE_IsParentProcess() && BrowserTabsRemoteAutostart() &&
6092 mozilla::jni::IsAvailable();
6093 #else
6094 return XRE_IsParentProcess() && BrowserTabsRemoteAutostart();
6095 #endif
6098 #define GECKO_PROCESS_TYPE(enum_value, enum_name, string_name, proc_typename, \
6099 process_bin_type, procinfo_typename, \
6100 webidl_typename, allcaps_name) \
6101 bool XRE_Is##proc_typename##Process() { \
6102 return XRE_GetProcessType() == GeckoProcessType_##enum_name; \
6104 #include "mozilla/GeckoProcessTypes.h"
6105 #undef GECKO_PROCESS_TYPE
6107 bool XRE_UseNativeEventProcessing() {
6108 switch (XRE_GetProcessType()) {
6109 #if defined(XP_MACOSX) || defined(XP_WIN)
6110 case GeckoProcessType_RDD:
6111 case GeckoProcessType_Socket:
6112 return false;
6113 case GeckoProcessType_Utility: {
6114 # if defined(XP_WIN)
6115 auto upc = mozilla::ipc::UtilityProcessChild::Get();
6116 MOZ_ASSERT(upc);
6118 using SboxKind = mozilla::ipc::SandboxingKind;
6119 // These processes are used as external hosts for accessing Windows
6120 // APIs which (may) require a Windows native event loop.
6121 return upc->mSandbox == SboxKind::WINDOWS_UTILS ||
6122 upc->mSandbox == SboxKind::WINDOWS_FILE_DIALOG;
6123 # else
6124 return false;
6125 # endif // defined(XP_WIN)
6127 #endif // defined(XP_MACOSX) || defined(XP_WIN)
6128 case GeckoProcessType_GMPlugin:
6129 return mozilla::gmp::GMPProcessChild::UseNativeEventProcessing();
6130 case GeckoProcessType_Content:
6131 return StaticPrefs::dom_ipc_useNativeEventProcessing_content();
6132 default:
6133 return true;
6137 namespace mozilla {
6139 uint32_t GetMaxWebProcessCount() {
6140 // multiOptOut is in int to allow us to run multiple experiments without
6141 // introducing multiple prefs a la the autostart.N prefs.
6142 if (Preferences::GetInt("dom.ipc.multiOptOut", 0) >=
6143 nsIXULRuntime::E10S_MULTI_EXPERIMENT) {
6144 return 1;
6147 const char* optInPref = "dom.ipc.processCount";
6148 uint32_t optInPrefValue = Preferences::GetInt(optInPref, 1);
6149 return std::max(1u, optInPrefValue);
6152 const char* PlatformBuildID() { return gToolkitBuildID; }
6154 } // namespace mozilla
6156 void SetupErrorHandling(const char* progname) {
6157 #ifdef XP_WIN
6158 /* On Windows XPSP3 and Windows Vista if DEP is configured off-by-default
6159 we still want DEP protection: enable it explicitly and programmatically.
6161 This function is not available on WinXPSP2 so we dynamically load it.
6164 HMODULE kernel32 = GetModuleHandleW(L"kernel32.dll");
6165 SetProcessDEPPolicyFunc _SetProcessDEPPolicy =
6166 (SetProcessDEPPolicyFunc)GetProcAddress(kernel32, "SetProcessDEPPolicy");
6167 if (_SetProcessDEPPolicy) _SetProcessDEPPolicy(PROCESS_DEP_ENABLE);
6168 #endif
6170 #ifdef XP_WIN
6171 // Suppress the "DLL Foo could not be found" dialog, such that if dependent
6172 // libraries (such as GDI+) are not preset, we gracefully fail to load those
6173 // XPCOM components, instead of being ungraceful.
6174 UINT realMode = SetErrorMode(0);
6175 realMode |= SEM_FAILCRITICALERRORS;
6176 // If XRE_NO_WINDOWS_CRASH_DIALOG is set, suppress displaying the "This
6177 // application has crashed" dialog box. This is mainly useful for
6178 // automated testing environments, e.g. tinderbox, where there's no need
6179 // for a dozen of the dialog boxes to litter the console
6180 if (getenv("XRE_NO_WINDOWS_CRASH_DIALOG"))
6181 realMode |= SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX;
6183 SetErrorMode(realMode);
6185 #endif
6187 InstallSignalHandlers(progname);
6189 // Unbuffer stdout, needed for tinderbox tests.
6190 setbuf(stdout, 0);
6193 static bool gRunSelfAsContentProc = false;
6195 void XRE_EnableSameExecutableForContentProc() {
6196 if (!PR_GetEnv("MOZ_SEPARATE_CHILD_PROCESS")) {
6197 gRunSelfAsContentProc = true;
6201 mozilla::BinPathType XRE_GetChildProcBinPathType(
6202 GeckoProcessType aProcessType) {
6203 MOZ_ASSERT(aProcessType != GeckoProcessType_Default);
6205 if (!gRunSelfAsContentProc) {
6206 return BinPathType::PluginContainer;
6209 #ifdef XP_WIN
6210 // On Windows, plugin-container may or may not be used depending on
6211 // the process type (e.g., actual plugins vs. content processes)
6212 switch (aProcessType) {
6213 # define GECKO_PROCESS_TYPE(enum_value, enum_name, string_name, \
6214 proc_typename, process_bin_type, \
6215 procinfo_typename, webidl_typename, allcaps_name) \
6216 case GeckoProcessType_##enum_name: \
6217 return BinPathType::process_bin_type;
6218 # include "mozilla/GeckoProcessTypes.h"
6219 # undef GECKO_PROCESS_TYPE
6220 default:
6221 return BinPathType::PluginContainer;
6223 #else
6224 // On (non-macOS) Unix, plugin-container isn't used (except in cases
6225 // like xpcshell that are handled by the gRunSelfAsContentProc check
6226 // above). It isn't necessary the way it is on other platforms, and
6227 // it interferes with using the fork server.
6228 return BinPathType::Self;
6229 #endif
6232 // From mozglue/static/rust/lib.rs
6233 extern "C" void install_rust_hooks();
6235 struct InstallRustHooks {
6236 InstallRustHooks() { install_rust_hooks(); }
6239 InstallRustHooks sInstallRustHooks;
6241 #ifdef MOZ_ASAN_REPORTER
6242 void setASanReporterPath(nsIFile* aDir) {
6243 nsCOMPtr<nsIFile> dir;
6244 aDir->Clone(getter_AddRefs(dir));
6246 dir->Append(u"asan"_ns);
6247 nsresult rv = dir->Create(nsIFile::DIRECTORY_TYPE, 0700);
6248 if (NS_WARN_IF(NS_FAILED(rv) && rv != NS_ERROR_FILE_ALREADY_EXISTS)) {
6249 MOZ_CRASH("[ASan Reporter] Unable to create crash directory.");
6252 dir->Append(u"ff_asan_log"_ns);
6254 # ifdef XP_WIN
6255 nsAutoString nspathW;
6256 rv = dir->GetPath(nspathW);
6257 NS_ConvertUTF16toUTF8 nspath(nspathW);
6258 # else
6259 nsAutoCString nspath;
6260 rv = dir->GetNativePath(nspath);
6261 # endif
6262 if (NS_FAILED(rv)) {
6263 MOZ_CRASH("[ASan Reporter] Unable to get native path for crash directory.");
6266 __sanitizer_set_report_path(nspath.get());
6268 #endif