Bug 1867925 - Mark some storage-access-api tests as intermittent after wpt-sync....
[gecko.git] / toolkit / xre / nsAppRunner.cpp
blobf1fc0af1f34d160556c0ec88e11d1bfe58e93b97
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/GleanPings.h"
40 #include "mozilla/widget/TextRecognition.h"
41 #include "BaseProfiler.h"
43 #include "nsAppRunner.h"
44 #include "mozilla/XREAppData.h"
45 #include "mozilla/Bootstrap.h"
46 #if defined(MOZ_UPDATER) && !defined(MOZ_WIDGET_ANDROID)
47 # include "nsUpdateDriver.h"
48 # include "nsUpdateSyncManager.h"
49 #endif
50 #include "ProfileReset.h"
52 #ifdef MOZ_INSTRUMENT_EVENT_LOOP
53 # include "EventTracer.h"
54 #endif
56 #ifdef XP_MACOSX
57 # include "nsVersionComparator.h"
58 # include "MacLaunchHelper.h"
59 # include "MacApplicationDelegate.h"
60 # include "MacAutoreleasePool.h"
61 # include "MacRunFromDmgUtils.h"
62 // these are needed for sysctl
63 # include <sys/types.h>
64 # include <sys/sysctl.h>
65 #endif
67 #include "prnetdb.h"
68 #include "prprf.h"
69 #include "prproces.h"
70 #include "prenv.h"
71 #include "prtime.h"
73 #include "nsIAppStartup.h"
74 #include "nsCategoryManagerUtils.h"
75 #include "nsIMutableArray.h"
76 #include "nsCommandLine.h"
77 #include "nsIComponentRegistrar.h"
78 #include "nsIDialogParamBlock.h"
79 #include "mozilla/ModuleUtils.h"
80 #include "nsIIOService.h"
81 #include "nsIObserverService.h"
82 #include "nsINativeAppSupport.h"
83 #include "nsIPlatformInfo.h"
84 #include "nsIProcess.h"
85 #include "nsIProfileUnlocker.h"
86 #include "nsIPromptService.h"
87 #include "nsIPropertyBag2.h"
88 #include "nsIServiceManager.h"
89 #include "nsIStringBundle.h"
90 #include "nsISupportsPrimitives.h"
91 #include "nsIToolkitProfile.h"
92 #include "nsToolkitProfileService.h"
93 #include "nsIURI.h"
94 #include "nsIURL.h"
95 #include "nsIWindowCreator.h"
96 #include "nsIWindowWatcher.h"
97 #include "nsIXULAppInfo.h"
98 #include "nsIXULRuntime.h"
99 #include "nsPIDOMWindow.h"
100 #include "nsIWidget.h"
101 #include "nsAppShellCID.h"
102 #include "mozilla/dom/quota/QuotaManager.h"
103 #include "mozilla/scache/StartupCache.h"
104 #include "gfxPlatform.h"
105 #include "PDMFactory.h"
106 #ifdef XP_MACOSX
107 # include "gfxPlatformMac.h"
108 #endif
110 #include "mozilla/Unused.h"
112 #ifdef XP_WIN
113 # include "nsIWinAppHelper.h"
114 # include <windows.h>
115 # include <intrin.h>
116 # include <math.h>
117 # include "cairo/cairo-features.h"
118 # include "detect_win32k_conflicts.h"
119 # include "mozilla/PreXULSkeletonUI.h"
120 # include "mozilla/DllPrefetchExperimentRegistryInfo.h"
121 # include "mozilla/WindowsBCryptInitialization.h"
122 # include "mozilla/WindowsDllBlocklist.h"
123 # include "mozilla/WindowsMsctfInitialization.h"
124 # include "mozilla/WindowsProcessMitigations.h"
125 # include "mozilla/WindowsVersion.h"
126 # include "mozilla/WinHeaderOnlyUtils.h"
127 # include "mozilla/mscom/ProcessRuntime.h"
128 # include "mozilla/mscom/ProfilerMarkers.h"
129 # include "WinTokenUtils.h"
131 # if defined(MOZ_LAUNCHER_PROCESS)
132 # include "mozilla/LauncherRegistryInfo.h"
133 # endif
135 # if defined(MOZ_DEFAULT_BROWSER_AGENT)
136 # include "nsIWindowsRegKey.h"
137 # endif
139 # ifndef PROCESS_DEP_ENABLE
140 # define PROCESS_DEP_ENABLE 0x1
141 # endif
142 #endif
144 #if defined(MOZ_SANDBOX)
145 # include "mozilla/SandboxSettings.h"
146 #endif
148 #ifdef ACCESSIBILITY
149 # include "nsAccessibilityService.h"
150 # if defined(XP_WIN)
151 # include "mozilla/a11y/Compatibility.h"
152 # include "mozilla/a11y/Platform.h"
153 # endif
154 #endif
156 #include "nsCRT.h"
157 #include "nsCOMPtr.h"
158 #include "nsDirectoryServiceDefs.h"
159 #include "nsDirectoryServiceUtils.h"
160 #include "nsEmbedCID.h"
161 #include "nsIDUtils.h"
162 #include "nsNetUtil.h"
163 #include "nsReadableUtils.h"
164 #include "nsXPCOM.h"
165 #include "nsXPCOMCIDInternal.h"
166 #include "nsString.h"
167 #include "nsPrintfCString.h"
168 #include "nsVersionComparator.h"
170 #include "nsAppDirectoryServiceDefs.h"
171 #include "nsXULAppAPI.h"
172 #include "nsXREDirProvider.h"
174 #include "nsINIParser.h"
175 #include "mozilla/Omnijar.h"
176 #include "mozilla/StartupTimeline.h"
177 #include "mozilla/LateWriteChecks.h"
179 #include <stdlib.h>
180 #include <locale.h>
182 #ifdef XP_UNIX
183 # include <errno.h>
184 # include <pwd.h>
185 # include <string.h>
186 # include <sys/resource.h>
187 # include <sys/stat.h>
188 # include <unistd.h>
189 #endif
191 #ifdef XP_WIN
192 # include <process.h>
193 # include <shlobj.h>
194 # include "mozilla/WinDllServices.h"
195 # include "nsThreadUtils.h"
196 # include "WinUtils.h"
197 #endif
199 #ifdef XP_MACOSX
200 # include "nsILocalFileMac.h"
201 # include "nsCommandLineServiceMac.h"
202 #endif
204 // for X remote support
205 #if defined(MOZ_HAS_REMOTE)
206 # include "nsRemoteService.h"
207 #endif
209 #if defined(DEBUG) && defined(XP_WIN)
210 # include <malloc.h>
211 #endif
213 #if defined(XP_MACOSX)
214 # include <Carbon/Carbon.h>
215 #endif
217 #ifdef DEBUG
218 # include "mozilla/Logging.h"
219 #endif
221 #ifdef MOZ_JPROF
222 # include "jprof.h"
223 #endif
225 #include "nsExceptionHandler.h"
226 #include "nsICrashReporter.h"
227 #include "nsIPrefService.h"
228 #include "nsIMemoryInfoDumper.h"
229 #if defined(XP_LINUX) && !defined(ANDROID)
230 # include "mozilla/widget/LSBUtils.h"
231 #endif
233 #include "base/command_line.h"
234 #include "GTestRunner.h"
236 #ifdef MOZ_WIDGET_ANDROID
237 # include "mozilla/java/GeckoAppShellWrappers.h"
238 #endif
240 #if defined(MOZ_SANDBOX)
241 # if defined(XP_LINUX) && !defined(ANDROID)
242 # include "mozilla/SandboxInfo.h"
243 # elif defined(XP_WIN)
244 # include "sandboxBroker.h"
245 # endif
246 #endif
248 #ifdef MOZ_CODE_COVERAGE
249 # include "mozilla/CodeCoverageHandler.h"
250 #endif
252 #include "GMPProcessChild.h"
253 #include "SafeMode.h"
255 #ifdef MOZ_BACKGROUNDTASKS
256 # include "mozilla/BackgroundTasks.h"
257 # include "nsIPowerManagerService.h"
258 # include "nsIStringBundle.h"
259 #endif
261 #ifdef USE_GLX_TEST
262 # include "mozilla/GUniquePtr.h"
263 # include "mozilla/GfxInfo.h"
264 #endif
266 #ifdef MOZ_WIDGET_GTK
267 # include "nsAppShell.h"
268 #endif
270 extern uint32_t gRestartMode;
271 extern void InstallSignalHandlers(const char* ProgramName);
273 #define FILE_COMPATIBILITY_INFO "compatibility.ini"_ns
274 #define FILE_INVALIDATE_CACHES ".purgecaches"_ns
275 #define FILE_STARTUP_INCOMPLETE u".startup-incomplete"_ns
277 #if defined(MOZ_BLOCK_PROFILE_DOWNGRADE) || defined(MOZ_LAUNCHER_PROCESS) || \
278 defined(MOZ_DEFAULT_BROWSER_AGENT)
279 static const char kPrefHealthReportUploadEnabled[] =
280 "datareporting.healthreport.uploadEnabled";
281 #endif // defined(MOZ_BLOCK_PROFILE_DOWNGRADE) || defined(MOZ_LAUNCHER_PROCESS)
282 // || defined(MOZ_DEFAULT_BROWSER_AGENT)
283 #if defined(MOZ_DEFAULT_BROWSER_AGENT)
284 static const char kPrefDefaultAgentEnabled[] = "default-browser-agent.enabled";
286 static const char kPrefServicesSettingsServer[] = "services.settings.server";
287 static const char kPrefSecurityContentSignatureRootHash[] =
288 "security.content.signature.root_hash";
289 static const char kPrefSetDefaultBrowserUserChoicePref[] =
290 "browser.shell.setDefaultBrowserUserChoice";
291 #endif // defined(MOZ_DEFAULT_BROWSER_AGENT)
293 #if defined(XP_WIN)
294 static const char kPrefThemeId[] = "extensions.activeThemeID";
295 static const char kPrefBrowserStartupBlankWindow[] =
296 "browser.startup.blankWindow";
297 static const char kPrefPreXulSkeletonUI[] = "browser.startup.preXulSkeletonUI";
298 #endif // defined(XP_WIN)
300 #if defined(MOZ_WIDGET_GTK)
301 constexpr nsLiteralCString kStartupTokenNames[] = {
302 "XDG_ACTIVATION_TOKEN"_ns,
303 "DESKTOP_STARTUP_ID"_ns,
305 #endif
307 int gArgc;
308 char** gArgv;
310 static const char gToolkitVersion[] = MOZ_STRINGIFY(GRE_MILESTONE);
311 // The gToolkitBuildID global is defined to MOZ_BUILDID via gen_buildid.py
312 // in toolkit/library. See related comment in toolkit/library/moz.build.
313 extern const char gToolkitBuildID[];
315 static nsIProfileLock* gProfileLock;
316 #if defined(MOZ_HAS_REMOTE)
317 static nsRemoteService* gRemoteService;
318 bool gRestartWithoutRemote = false;
319 #endif
321 int gRestartArgc;
322 char** gRestartArgv;
324 // If gRestartedByOS is set, we were automatically restarted by the OS.
325 bool gRestartedByOS = false;
327 bool gIsGtest = false;
329 bool gKioskMode = false;
330 int gKioskMonitor = -1;
332 bool gAllowContentAnalysis = false;
334 nsString gAbsoluteArgv0Path;
336 #if defined(XP_WIN)
337 nsString gProcessStartupShortcut;
338 #endif
340 #if defined(MOZ_WIDGET_GTK)
341 # include <glib.h>
342 # include "mozilla/WidgetUtilsGtk.h"
343 # include <gtk/gtk.h>
344 # ifdef MOZ_WAYLAND
345 # include <gdk/gdkwayland.h>
346 # include "mozilla/widget/nsWaylandDisplay.h"
347 # endif
348 # ifdef MOZ_X11
349 # include <gdk/gdkx.h>
350 # endif /* MOZ_X11 */
351 #endif
352 #include "BinaryPath.h"
354 #ifdef FUZZING
355 # include "FuzzerRunner.h"
357 namespace mozilla {
358 FuzzerRunner* fuzzerRunner = 0;
359 } // namespace mozilla
361 # ifdef LIBFUZZER
362 void XRE_LibFuzzerSetDriver(LibFuzzerDriver aDriver) {
363 mozilla::fuzzerRunner->setParams(aDriver);
365 # endif
366 #endif // FUZZING
368 // Undo X11/X.h's definition of None
369 #undef None
371 namespace mozilla {
372 int (*RunGTest)(int*, char**) = 0;
374 bool RunningGTest() { return RunGTest; }
375 } // namespace mozilla
377 using namespace mozilla;
378 using namespace mozilla::widget;
379 using namespace mozilla::startup;
380 using mozilla::Unused;
381 using mozilla::dom::ContentChild;
382 using mozilla::dom::ContentParent;
383 using mozilla::dom::quota::QuotaManager;
384 using mozilla::intl::LocaleService;
385 using mozilla::scache::StartupCache;
387 // Save the given word to the specified environment variable.
388 static void MOZ_NEVER_INLINE SaveWordToEnv(const char* name,
389 const nsACString& word) {
390 char* expr =
391 Smprintf("%s=%s", name, PromiseFlatCString(word).get()).release();
392 if (expr) PR_SetEnv(expr);
393 // We intentionally leak |expr| here since it is required by PR_SetEnv.
396 // Save the path of the given file to the specified environment variable.
397 static void SaveFileToEnv(const char* name, nsIFile* file) {
398 #ifdef XP_WIN
399 nsAutoString path;
400 file->GetPath(path);
401 SetEnvironmentVariableW(NS_ConvertASCIItoUTF16(name).get(), path.get());
402 #else
403 nsAutoCString path;
404 file->GetNativePath(path);
405 SaveWordToEnv(name, path);
406 #endif
409 static bool gIsExpectedExit = false;
411 void MozExpectedExit() { gIsExpectedExit = true; }
414 * Runs atexit() to catch unexpected exit from 3rd party libraries like the
415 * Intel graphics driver calling exit in an error condition. When they
416 * call exit() to report an error we won't shutdown correctly and wont catch
417 * the issue with our crash reporter.
419 static void UnexpectedExit() {
420 if (!gIsExpectedExit) {
421 gIsExpectedExit = true; // Don't risk re-entrency issues when crashing.
422 MOZ_CRASH("Exit called by third party code.");
426 #if defined(MOZ_WAYLAND)
427 bool IsWaylandEnabled() {
428 static bool isWaylandEnabled = []() {
429 const char* waylandDisplay = PR_GetEnv("WAYLAND_DISPLAY");
430 if (!waylandDisplay) {
431 return false;
433 if (!PR_GetEnv("DISPLAY")) {
434 // No X11 display, so try to run wayland.
435 return true;
437 // MOZ_ENABLE_WAYLAND is our primary Wayland on/off switch.
438 if (const char* waylandPref = PR_GetEnv("MOZ_ENABLE_WAYLAND")) {
439 return *waylandPref == '1';
441 if (const char* backendPref = PR_GetEnv("GDK_BACKEND")) {
442 if (!strncmp(backendPref, "wayland", 7)) {
443 NS_WARNING(
444 "Wayland backend should be enabled by MOZ_ENABLE_WAYLAND=1."
445 "GDK_BACKEND is a Gtk3 debug variable and may cause issues.");
446 return true;
449 // Enable by default when we're running on a recent enough GTK version. We'd
450 // like to check further details like compositor version and so on ideally
451 // to make sure we don't enable it on old Mutter or what not, but we can't,
452 // so let's assume that if the user is running on a Wayland session by
453 // default we're ok, since either the distro has enabled Wayland by default,
454 // or the user has gone out of their way to use Wayland.
455 return !gtk_check_version(3, 24, 30);
456 }();
457 return isWaylandEnabled;
459 #else
460 bool IsWaylandEnabled() { return false; }
461 #endif
464 * Output a string to the user. This method is really only meant to be used to
465 * output last-ditch error messages designed for developers NOT END USERS.
467 * @param isError
468 * Pass true to indicate severe errors.
469 * @param fmt
470 * printf-style format string followed by arguments.
472 static MOZ_FORMAT_PRINTF(2, 3) void Output(bool isError, const char* fmt, ...) {
473 va_list ap;
474 va_start(ap, fmt);
476 #if defined(XP_WIN) && !MOZ_WINCONSOLE
477 SmprintfPointer msg = mozilla::Vsmprintf(fmt, ap);
478 if (msg) {
479 UINT flags = MB_OK;
480 if (isError)
481 flags |= MB_ICONERROR;
482 else
483 flags |= MB_ICONINFORMATION;
485 wchar_t wide_msg[1024];
486 MultiByteToWideChar(CP_ACP, 0, msg.get(), -1, wide_msg,
487 sizeof(wide_msg) / sizeof(wchar_t));
489 MessageBoxW(nullptr, wide_msg, L"XULRunner", flags);
491 #elif defined(MOZ_WIDGET_ANDROID)
492 SmprintfPointer msg = mozilla::Vsmprintf(fmt, ap);
493 if (msg) {
494 __android_log_print(isError ? ANDROID_LOG_ERROR : ANDROID_LOG_INFO,
495 "GeckoRuntime", "%s", msg.get());
497 #else
498 vfprintf(stderr, fmt, ap);
499 #endif
501 va_end(ap);
505 * Check for a commandline flag. If the flag takes a parameter, the
506 * parameter is returned in aParam. Flags may be in the form -arg or
507 * --arg (or /arg on win32).
509 * @param aArg the parameter to check. Must be lowercase.
510 * @param aParam if non-null, the -arg <data> will be stored in this pointer.
511 * This is *not* allocated, but rather a pointer to the argv data.
512 * @param aFlags flags @see CheckArgFlag
514 static ArgResult CheckArg(const char* aArg, const char** aParam = nullptr,
515 CheckArgFlag aFlags = CheckArgFlag::RemoveArg) {
516 MOZ_ASSERT(gArgv, "gArgv must be initialized before CheckArg()");
517 return CheckArg(gArgc, gArgv, aArg, aParam, aFlags);
521 * Check for a commandline flag. Ignore data that's passed in with the flag.
522 * Flags may be in the form -arg or --arg (or /arg on win32).
523 * Will not remove flag if found.
525 * @param aArg the parameter to check. Must be lowercase.
527 static ArgResult CheckArgExists(const char* aArg) {
528 return CheckArg(aArg, nullptr, CheckArgFlag::None);
531 bool gSafeMode = false;
532 bool gFxREmbedded = false;
534 enum E10sStatus {
535 kE10sEnabledByDefault,
536 kE10sDisabledByUser,
537 kE10sForceDisabled,
540 static bool gBrowserTabsRemoteAutostart = false;
541 static E10sStatus gBrowserTabsRemoteStatus;
542 static bool gBrowserTabsRemoteAutostartInitialized = false;
544 namespace mozilla {
546 bool BrowserTabsRemoteAutostart() {
547 if (gBrowserTabsRemoteAutostartInitialized) {
548 return gBrowserTabsRemoteAutostart;
550 gBrowserTabsRemoteAutostartInitialized = true;
552 // If we're not in the parent process, we are running E10s.
553 if (!XRE_IsParentProcess()) {
554 gBrowserTabsRemoteAutostart = true;
555 return gBrowserTabsRemoteAutostart;
558 #if defined(MOZILLA_OFFICIAL) && MOZ_BUILD_APP_IS_BROWSER
559 bool allowSingleProcessOutsideAutomation = false;
560 #else
561 bool allowSingleProcessOutsideAutomation = true;
562 #endif
564 E10sStatus status = kE10sEnabledByDefault;
565 // We use "are non-local connections disabled" as a proxy for
566 // "are we running some kind of automated test". It would be nicer to use
567 // xpc::IsInAutomation(), but that depends on some prefs being set, which
568 // they are not in (at least) gtests (where we can't) and xpcshell.
569 // Long-term, hopefully we can make tests switch to environment variables
570 // to disable e10s and then we can get rid of this.
571 if (allowSingleProcessOutsideAutomation ||
572 xpc::AreNonLocalConnectionsDisabled()) {
573 bool optInPref =
574 Preferences::GetBool("browser.tabs.remote.autostart", true);
576 if (optInPref) {
577 gBrowserTabsRemoteAutostart = true;
578 } else {
579 status = kE10sDisabledByUser;
581 } else {
582 gBrowserTabsRemoteAutostart = true;
585 // Uber override pref for emergency blocking
586 if (gBrowserTabsRemoteAutostart) {
587 const char* forceDisable = PR_GetEnv("MOZ_FORCE_DISABLE_E10S");
588 #if defined(MOZ_WIDGET_ANDROID)
589 // We need this for xpcshell on Android
590 if (forceDisable && *forceDisable) {
591 #else
592 // The environment variable must match the application version to apply.
593 if (forceDisable && gAppData && !strcmp(forceDisable, gAppData->version)) {
594 #endif
595 gBrowserTabsRemoteAutostart = false;
596 status = kE10sForceDisabled;
600 gBrowserTabsRemoteStatus = status;
602 return gBrowserTabsRemoteAutostart;
605 } // namespace mozilla
607 // Win32k Infrastructure ==============================================
609 // This bool tells us if we have initialized the following two statics
610 // upon startup.
612 static bool gWin32kInitialized = false;
614 // Win32k Lockdown for the current session is determined once, at startup,
615 // and then remains the same for the duration of the session.
617 static nsIXULRuntime::ContentWin32kLockdownState gWin32kStatus;
619 // The status of the win32k experiment. It is determined once, at startup,
620 // and then remains the same for the duration of the session.
622 static nsIXULRuntime::ExperimentStatus gWin32kExperimentStatus =
623 nsIXULRuntime::eExperimentStatusUnenrolled;
625 #ifdef XP_WIN
626 // The states for win32k lockdown can be generalized to:
627 // - User doesn't meet requirements (bad OS, webrender, remotegl) aka
628 // PersistentRequirement
629 // - User has Safe Mode enabled, Win32k Disabled by Env Var, or E10S disabled
630 // by Env Var aka TemporaryRequirement
631 // - User has set the win32k pref to something non-default aka NonDefaultPref
632 // - User has been enrolled in the experiment and does what it says aka
633 // Enrolled
634 // - User does the default aka Default
636 // We expect the below behvaior. In the code, there may be references to these
637 // behaviors (e.g. [A]) but not always.
639 // [A] Becoming enrolled in the experiment while NonDefaultPref disqualifies
640 // you upon next browser start
641 // [B] Becoming enrolled in the experiment while PersistentRequirement
642 // disqualifies you upon next browser start
643 // [C] Becoming enrolled in the experiment while TemporaryRequirement does not
644 // disqualify you
645 // [D] Becoming enrolled in the experiment will only take effect after restart
646 // [E] While enrolled, becoming PersistentRequirement will not disqualify you
647 // until browser restart, but if the state is present at browser start,
648 // will disqualify you. Additionally, it will not affect the session value
649 // of gWin32kStatus.
650 // XXX(bobowen): I hope both webrender and wbgl.out-of-process require a
651 // restart to take effect!
652 // [F] While enrolled, becoming NonDefaultPref will disqualify you upon next
653 // browser start
654 // [G] While enrolled, becoming TemporaryRequirement will _not_ disqualify you,
655 // but the session status will prevent win32k lockdown from taking effect.
657 // The win32k pref
658 static const char kPrefWin32k[] = "security.sandbox.content.win32k-disable";
660 // The current enrollment status as controlled by Normandy. This value is only
661 // stored in the default preference branch, and is not persisted across
662 // sessions by the preference service. It therefore isn't available early
663 // enough at startup, and needs to be synced to a preference in the user
664 // branch which is persisted across sessions.
665 static const char kPrefWin32kExperimentEnrollmentStatus[] =
666 "security.sandbox.content.win32k-experiment.enrollmentStatus";
668 // The enrollment status to be used at browser startup. This automatically
669 // synced from the above enrollmentStatus preference whenever the latter is
670 // changed. We reused the Fission experiment enum - it can have any of the
671 // values defined in the `nsIXULRuntime_ExperimentStatus` enum _except_ rollout.
672 // Meanings are documented in the declaration of
673 // `nsIXULRuntime.fissionExperimentStatus`
674 static const char kPrefWin32kExperimentStartupEnrollmentStatus[] =
675 "security.sandbox.content.win32k-experiment.startupEnrollmentStatus";
677 namespace mozilla {
679 bool Win32kExperimentEnrolled() {
680 MOZ_ASSERT(XRE_IsParentProcess());
681 return gWin32kExperimentStatus == nsIXULRuntime::eExperimentStatusControl ||
682 gWin32kExperimentStatus == nsIXULRuntime::eExperimentStatusTreatment;
685 } // namespace mozilla
687 static bool Win32kRequirementsUnsatisfied(
688 nsIXULRuntime::ContentWin32kLockdownState aStatus) {
689 return aStatus == nsIXULRuntime::ContentWin32kLockdownState::
690 OperatingSystemNotSupported ||
691 aStatus ==
692 nsIXULRuntime::ContentWin32kLockdownState::MissingWebRender ||
693 aStatus ==
694 nsIXULRuntime::ContentWin32kLockdownState::MissingRemoteWebGL ||
695 aStatus ==
696 nsIXULRuntime::ContentWin32kLockdownState::DecodersArentRemote;
699 static void Win32kExperimentDisqualify() {
700 MOZ_ASSERT(XRE_IsParentProcess());
701 Preferences::SetUint(kPrefWin32kExperimentEnrollmentStatus,
702 nsIXULRuntime::eExperimentStatusDisqualified);
705 static void OnWin32kEnrollmentStatusChanged(const char* aPref, void* aData) {
706 auto newStatusInt =
707 Preferences::GetUint(kPrefWin32kExperimentEnrollmentStatus,
708 nsIXULRuntime::eExperimentStatusUnenrolled);
709 auto newStatus = newStatusInt < nsIXULRuntime::eExperimentStatusCount
710 ? nsIXULRuntime::ExperimentStatus(newStatusInt)
711 : nsIXULRuntime::eExperimentStatusDisqualified;
713 // Set the startup pref for next browser start [D]
714 Preferences::SetUint(kPrefWin32kExperimentStartupEnrollmentStatus, newStatus);
717 namespace {
718 // This observer is notified during `profile-before-change`, and ensures that
719 // the experiment enrollment status is synced over before the browser shuts
720 // down, even if it was not modified since win32k was initialized.
721 class Win32kEnrollmentStatusShutdownObserver final : public nsIObserver {
722 public:
723 NS_DECL_ISUPPORTS
725 NS_IMETHOD Observe(nsISupports* aSubject, const char* aTopic,
726 const char16_t* aData) override {
727 MOZ_ASSERT(!strcmp("profile-before-change", aTopic));
728 OnWin32kEnrollmentStatusChanged(kPrefWin32kExperimentEnrollmentStatus,
729 nullptr);
730 return NS_OK;
733 private:
734 ~Win32kEnrollmentStatusShutdownObserver() = default;
736 NS_IMPL_ISUPPORTS(Win32kEnrollmentStatusShutdownObserver, nsIObserver)
737 } // namespace
739 static void OnWin32kChanged(const char* aPref, void* aData) {
740 // If we're actively enrolled in the Win32k experiment, disqualify the user
741 // from the experiment if the Win32k pref is modified. [F]
742 if (Win32kExperimentEnrolled() && Preferences::HasUserValue(kPrefWin32k)) {
743 Win32kExperimentDisqualify();
747 #endif // XP_WIN
749 namespace mozilla {
750 void EnsureWin32kInitialized();
753 nsIXULRuntime::ContentWin32kLockdownState GetLiveWin32kLockdownState() {
754 #ifdef XP_WIN
756 // HasUserValue The Pref functions can only be called on main thread
757 MOZ_ASSERT(NS_IsMainThread());
759 # ifdef MOZ_BACKGROUNDTASKS
760 if (BackgroundTasks::IsBackgroundTaskMode()) {
761 // Let's bail out before loading all the graphics libs.
762 return nsIXULRuntime::ContentWin32kLockdownState::DisabledByDefault;
764 # endif
766 mozilla::EnsureWin32kInitialized();
767 gfxPlatform::GetPlatform();
769 if (gSafeMode) {
770 return nsIXULRuntime::ContentWin32kLockdownState::DisabledBySafeMode;
773 if (EnvHasValue("MOZ_ENABLE_WIN32K")) {
774 return nsIXULRuntime::ContentWin32kLockdownState::DisabledByEnvVar;
777 if (!mozilla::BrowserTabsRemoteAutostart()) {
778 return nsIXULRuntime::ContentWin32kLockdownState::DisabledByE10S;
781 // Win32k lockdown is available on Win8+, but we are initially limiting it to
782 // Windows 10 v1709 (build 16299) or later. Before this COM initialization
783 // currently fails if user32.dll has loaded before it is called.
784 if (!IsWin10FallCreatorsUpdateOrLater()) {
785 return nsIXULRuntime::ContentWin32kLockdownState::
786 OperatingSystemNotSupported;
790 ConflictingMitigationStatus conflictingMitigationStatus = {};
791 if (!detect_win32k_conflicting_mitigations(&conflictingMitigationStatus)) {
792 return nsIXULRuntime::ContentWin32kLockdownState::
793 IncompatibleMitigationPolicy;
795 if (conflictingMitigationStatus.caller_check ||
796 conflictingMitigationStatus.sim_exec ||
797 conflictingMitigationStatus.stack_pivot) {
798 return nsIXULRuntime::ContentWin32kLockdownState::
799 IncompatibleMitigationPolicy;
803 // Non-native theming is required as well
804 if (!StaticPrefs::widget_non_native_theme_enabled()) {
805 return nsIXULRuntime::ContentWin32kLockdownState::MissingNonNativeTheming;
808 // Win32k Lockdown requires Remote WebGL, but it may be disabled on
809 // certain hardware or virtual machines.
810 if (!gfx::gfxVars::AllowWebglOop() || !StaticPrefs::webgl_out_of_process()) {
811 return nsIXULRuntime::ContentWin32kLockdownState::MissingRemoteWebGL;
814 // Some (not sure exactly which) decoders are not compatible
815 if (!PDMFactory::AllDecodersAreRemote()) {
816 return nsIXULRuntime::ContentWin32kLockdownState::DecodersArentRemote;
819 bool prefSetByUser =
820 Preferences::HasUserValue("security.sandbox.content.win32k-disable");
821 bool prefValue = Preferences::GetBool(
822 "security.sandbox.content.win32k-disable", false, PrefValueKind::User);
823 bool defaultValue = Preferences::GetBool(
824 "security.sandbox.content.win32k-disable", false, PrefValueKind::Default);
826 if (prefSetByUser) {
827 if (prefValue) {
828 return nsIXULRuntime::ContentWin32kLockdownState::EnabledByUserPref;
829 } else {
830 return nsIXULRuntime::ContentWin32kLockdownState::DisabledByUserPref;
834 if (gWin32kExperimentStatus ==
835 nsIXULRuntime::ExperimentStatus::eExperimentStatusControl) {
836 return nsIXULRuntime::ContentWin32kLockdownState::DisabledByControlGroup;
837 } else if (gWin32kExperimentStatus ==
838 nsIXULRuntime::ExperimentStatus::eExperimentStatusTreatment) {
839 return nsIXULRuntime::ContentWin32kLockdownState::EnabledByTreatmentGroup;
842 if (defaultValue) {
843 return nsIXULRuntime::ContentWin32kLockdownState::EnabledByDefault;
844 } else {
845 return nsIXULRuntime::ContentWin32kLockdownState::DisabledByDefault;
848 #else
850 return nsIXULRuntime::ContentWin32kLockdownState::OperatingSystemNotSupported;
852 #endif
855 namespace mozilla {
857 void EnsureWin32kInitialized() {
858 if (gWin32kInitialized) {
859 return;
861 gWin32kInitialized = true;
863 #ifdef XP_WIN
865 // Initialize the Win32k experiment, configuring win32k's
866 // default, before checking other overrides. This allows opting-out of a
867 // Win32k experiment through about:preferences or about:config from a
868 // safemode session.
869 uint32_t experimentRaw =
870 Preferences::GetUint(kPrefWin32kExperimentStartupEnrollmentStatus,
871 nsIXULRuntime::eExperimentStatusUnenrolled);
872 gWin32kExperimentStatus =
873 experimentRaw < nsIXULRuntime::eExperimentStatusCount
874 ? nsIXULRuntime::ExperimentStatus(experimentRaw)
875 : nsIXULRuntime::eExperimentStatusDisqualified;
877 // Watch the experiment enrollment status pref to detect experiment
878 // disqualification, and ensure it is propagated for the next restart.
879 Preferences::RegisterCallback(&OnWin32kEnrollmentStatusChanged,
880 kPrefWin32kExperimentEnrollmentStatus);
881 if (nsCOMPtr<nsIObserverService> observerService =
882 mozilla::services::GetObserverService()) {
883 nsCOMPtr<nsIObserver> shutdownObserver =
884 new Win32kEnrollmentStatusShutdownObserver();
885 observerService->AddObserver(shutdownObserver, "profile-before-change",
886 false);
889 // If the user no longer qualifies because they edited a required pref, check
890 // that. [B] [E]
891 auto tmpStatus = GetLiveWin32kLockdownState();
892 if (Win32kExperimentEnrolled() && Win32kRequirementsUnsatisfied(tmpStatus)) {
893 Win32kExperimentDisqualify();
894 gWin32kExperimentStatus = nsIXULRuntime::eExperimentStatusDisqualified;
897 // If the user has overridden an active experiment by setting a user value for
898 // "security.sandbox.content.win32k-disable", disqualify the user from the
899 // experiment. [A] [F]
900 if (Preferences::HasUserValue(kPrefWin32k) && Win32kExperimentEnrolled()) {
901 Win32kExperimentDisqualify();
902 gWin32kExperimentStatus = nsIXULRuntime::eExperimentStatusDisqualified;
905 // Unlike Fission, we do not configure the default branch based on experiment
906 // enrollment status. Instead we check the startupEnrollmentPref in
907 // GetContentWin32kLockdownState()
909 Preferences::RegisterCallback(&OnWin32kChanged, kPrefWin32k);
911 // Set the state
912 gWin32kStatus = GetLiveWin32kLockdownState();
914 #else
915 gWin32kStatus =
916 nsIXULRuntime::ContentWin32kLockdownState::OperatingSystemNotSupported;
917 gWin32kExperimentStatus = nsIXULRuntime::eExperimentStatusUnenrolled;
919 #endif // XP_WIN
922 nsIXULRuntime::ContentWin32kLockdownState GetWin32kLockdownState() {
923 #ifdef XP_WIN
925 mozilla::EnsureWin32kInitialized();
926 return gWin32kStatus;
928 #else
930 return nsIXULRuntime::ContentWin32kLockdownState::OperatingSystemNotSupported;
932 #endif
935 } // namespace mozilla
937 // End Win32k Infrastructure ==========================================
939 // Fission Infrastructure =============================================
941 // Fission enablement for the current session is determined once, at startup,
942 // and then remains the same for the duration of the session.
944 // The following factors determine whether or not Fission is enabled for a
945 // session, in order of precedence:
947 // - Safe mode: In safe mode, Fission is never enabled.
949 // - The MOZ_FORCE_ENABLE_FISSION environment variable: If set to any value,
950 // Fission will be enabled.
952 // - The 'fission.autostart' preference, if it has been configured by the user.
953 static const char kPrefFissionAutostart[] = "fission.autostart";
955 // The computed FissionAutostart value for the session, read by content
956 // processes to initialize gFissionAutostart.
958 // This pref is locked, and only configured on the default branch, so should
959 // never be persisted in a profile.
960 static const char kPrefFissionAutostartSession[] = "fission.autostart.session";
963 // The computed FissionAutostart value for the session, read by content
964 // processes to initialize gFissionAutostart.
966 static bool gFissionAutostart = false;
967 static bool gFissionAutostartInitialized = false;
968 static nsIXULRuntime::FissionDecisionStatus gFissionDecisionStatus;
969 static void EnsureFissionAutostartInitialized() {
970 if (gFissionAutostartInitialized) {
971 return;
973 gFissionAutostartInitialized = true;
975 if (!XRE_IsParentProcess()) {
976 // This pref is configured for the current session by the parent process.
977 gFissionAutostart = Preferences::GetBool(kPrefFissionAutostartSession,
978 false, PrefValueKind::Default);
979 return;
982 if (!BrowserTabsRemoteAutostart()) {
983 gFissionAutostart = false;
984 if (gBrowserTabsRemoteStatus == kE10sForceDisabled) {
985 gFissionDecisionStatus = nsIXULRuntime::eFissionDisabledByE10sEnv;
986 } else {
987 gFissionDecisionStatus = nsIXULRuntime::eFissionDisabledByE10sOther;
989 } else if (EnvHasValue("MOZ_FORCE_ENABLE_FISSION")) {
990 gFissionAutostart = true;
991 gFissionDecisionStatus = nsIXULRuntime::eFissionEnabledByEnv;
992 } else if (EnvHasValue("MOZ_FORCE_DISABLE_FISSION")) {
993 gFissionAutostart = false;
994 gFissionDecisionStatus = nsIXULRuntime::eFissionDisabledByEnv;
995 } else {
996 // NOTE: This will take into account changes to the default due to
997 // `InitializeFissionExperimentStatus`.
998 gFissionAutostart = Preferences::GetBool(kPrefFissionAutostart, false);
999 if (Preferences::HasUserValue(kPrefFissionAutostart)) {
1000 gFissionDecisionStatus = gFissionAutostart
1001 ? nsIXULRuntime::eFissionEnabledByUserPref
1002 : nsIXULRuntime::eFissionDisabledByUserPref;
1003 } else {
1004 gFissionDecisionStatus = gFissionAutostart
1005 ? nsIXULRuntime::eFissionEnabledByDefault
1006 : nsIXULRuntime::eFissionDisabledByDefault;
1010 // Content processes cannot run the same logic as we're running in the parent
1011 // process, as the current value of various preferences may have changed
1012 // between launches. Instead, the content process will read the default branch
1013 // of the locked `fission.autostart.session` preference to determine the value
1014 // determined by this method.
1015 Preferences::Unlock(kPrefFissionAutostartSession);
1016 Preferences::ClearUser(kPrefFissionAutostartSession);
1017 Preferences::SetBool(kPrefFissionAutostartSession, gFissionAutostart,
1018 PrefValueKind::Default);
1019 Preferences::Lock(kPrefFissionAutostartSession);
1022 namespace mozilla {
1024 bool FissionAutostart() {
1025 EnsureFissionAutostartInitialized();
1026 return gFissionAutostart;
1029 } // namespace mozilla
1031 // End Fission Infrastructure =========================================
1033 namespace mozilla {
1035 bool SessionHistoryInParent() {
1036 return FissionAutostart() ||
1037 !StaticPrefs::
1038 fission_disableSessionHistoryInParent_AtStartup_DoNotUseDirectly();
1041 bool BFCacheInParent() {
1042 return SessionHistoryInParent() &&
1043 StaticPrefs::fission_bfcacheInParent_DoNotUseDirectly();
1046 } // namespace mozilla
1049 * The nsXULAppInfo object implements nsIFactory so that it can be its own
1050 * singleton.
1052 class nsXULAppInfo : public nsIXULAppInfo,
1053 #ifdef XP_WIN
1054 public nsIWinAppHelper,
1055 #endif
1056 public nsICrashReporter,
1057 public nsIFinishDumpingCallback,
1058 public nsIXULRuntime
1061 public:
1062 constexpr nsXULAppInfo() = default;
1063 NS_DECL_ISUPPORTS_INHERITED
1064 NS_DECL_NSIPLATFORMINFO
1065 NS_DECL_NSIXULAPPINFO
1066 NS_DECL_NSIXULRUNTIME
1067 NS_DECL_NSICRASHREPORTER
1068 NS_DECL_NSIFINISHDUMPINGCALLBACK
1069 #ifdef XP_WIN
1070 NS_DECL_NSIWINAPPHELPER
1071 #endif
1074 NS_INTERFACE_MAP_BEGIN(nsXULAppInfo)
1075 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXULRuntime)
1076 NS_INTERFACE_MAP_ENTRY(nsIXULRuntime)
1077 #ifdef XP_WIN
1078 NS_INTERFACE_MAP_ENTRY(nsIWinAppHelper)
1079 #endif
1080 NS_INTERFACE_MAP_ENTRY(nsICrashReporter)
1081 NS_INTERFACE_MAP_ENTRY(nsIFinishDumpingCallback)
1082 NS_INTERFACE_MAP_ENTRY(nsIPlatformInfo)
1083 NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIXULAppInfo,
1084 gAppData || XRE_IsContentProcess())
1085 NS_INTERFACE_MAP_END
1087 NS_IMETHODIMP_(MozExternalRefCountType)
1088 nsXULAppInfo::AddRef() { return 1; }
1090 NS_IMETHODIMP_(MozExternalRefCountType)
1091 nsXULAppInfo::Release() { return 1; }
1093 NS_IMETHODIMP
1094 nsXULAppInfo::GetVendor(nsACString& aResult) {
1095 if (XRE_IsContentProcess()) {
1096 ContentChild* cc = ContentChild::GetSingleton();
1097 aResult = cc->GetAppInfo().vendor;
1098 return NS_OK;
1100 aResult.Assign(gAppData->vendor);
1102 return NS_OK;
1105 NS_IMETHODIMP
1106 nsXULAppInfo::GetName(nsACString& aResult) {
1107 if (XRE_IsContentProcess()) {
1108 ContentChild* cc = ContentChild::GetSingleton();
1109 aResult = cc->GetAppInfo().name;
1110 return NS_OK;
1113 #ifdef MOZ_WIDGET_ANDROID
1114 nsCString name = java::GeckoAppShell::GetAppName()->ToCString();
1115 aResult.Assign(std::move(name));
1116 #else
1117 aResult.Assign(gAppData->name);
1118 #endif
1120 return NS_OK;
1123 NS_IMETHODIMP
1124 nsXULAppInfo::GetID(nsACString& aResult) {
1125 if (XRE_IsContentProcess()) {
1126 ContentChild* cc = ContentChild::GetSingleton();
1127 aResult = cc->GetAppInfo().ID;
1128 return NS_OK;
1130 aResult.Assign(gAppData->ID);
1132 return NS_OK;
1135 NS_IMETHODIMP
1136 nsXULAppInfo::GetVersion(nsACString& aResult) {
1137 if (XRE_IsContentProcess()) {
1138 ContentChild* cc = ContentChild::GetSingleton();
1139 aResult = cc->GetAppInfo().version;
1140 return NS_OK;
1142 aResult.Assign(gAppData->version);
1144 return NS_OK;
1147 NS_IMETHODIMP
1148 nsXULAppInfo::GetPlatformVersion(nsACString& aResult) {
1149 aResult.Assign(gToolkitVersion);
1151 return NS_OK;
1154 NS_IMETHODIMP
1155 nsXULAppInfo::GetAppBuildID(nsACString& aResult) {
1156 if (XRE_IsContentProcess()) {
1157 ContentChild* cc = ContentChild::GetSingleton();
1158 aResult = cc->GetAppInfo().buildID;
1159 return NS_OK;
1161 aResult.Assign(gAppData->buildID);
1163 return NS_OK;
1166 NS_IMETHODIMP
1167 nsXULAppInfo::GetPlatformBuildID(nsACString& aResult) {
1168 aResult.Assign(gToolkitBuildID);
1170 return NS_OK;
1173 NS_IMETHODIMP
1174 nsXULAppInfo::GetUAName(nsACString& aResult) {
1175 if (XRE_IsContentProcess()) {
1176 ContentChild* cc = ContentChild::GetSingleton();
1177 aResult = cc->GetAppInfo().UAName;
1178 return NS_OK;
1180 aResult.Assign(gAppData->UAName);
1182 return NS_OK;
1185 NS_IMETHODIMP
1186 nsXULAppInfo::GetSourceURL(nsACString& aResult) {
1187 if (XRE_IsContentProcess()) {
1188 ContentChild* cc = ContentChild::GetSingleton();
1189 aResult = cc->GetAppInfo().sourceURL;
1190 return NS_OK;
1192 aResult.Assign(gAppData->sourceURL);
1194 return NS_OK;
1197 NS_IMETHODIMP
1198 nsXULAppInfo::GetUpdateURL(nsACString& aResult) {
1199 if (XRE_IsContentProcess()) {
1200 ContentChild* cc = ContentChild::GetSingleton();
1201 aResult = cc->GetAppInfo().updateURL;
1202 return NS_OK;
1204 aResult.Assign(gAppData->updateURL);
1206 return NS_OK;
1209 NS_IMETHODIMP
1210 nsXULAppInfo::GetLogConsoleErrors(bool* aResult) {
1211 *aResult = gLogConsoleErrors;
1212 return NS_OK;
1215 NS_IMETHODIMP
1216 nsXULAppInfo::SetLogConsoleErrors(bool aValue) {
1217 gLogConsoleErrors = aValue;
1218 return NS_OK;
1221 NS_IMETHODIMP
1222 nsXULAppInfo::GetInSafeMode(bool* aResult) {
1223 *aResult = gSafeMode;
1224 return NS_OK;
1227 NS_IMETHODIMP
1228 nsXULAppInfo::GetOS(nsACString& aResult) {
1229 aResult.AssignLiteral(OS_TARGET);
1230 return NS_OK;
1233 NS_IMETHODIMP
1234 nsXULAppInfo::GetXPCOMABI(nsACString& aResult) {
1235 #ifdef TARGET_XPCOM_ABI
1236 aResult.AssignLiteral(TARGET_XPCOM_ABI);
1237 return NS_OK;
1238 #else
1239 return NS_ERROR_NOT_AVAILABLE;
1240 #endif
1243 NS_IMETHODIMP
1244 nsXULAppInfo::GetWidgetToolkit(nsACString& aResult) {
1245 aResult.AssignLiteral(MOZ_WIDGET_TOOLKIT);
1246 return NS_OK;
1249 // Ensure that the GeckoProcessType enum, defined in xpcom/build/nsXULAppAPI.h,
1250 // is synchronized with the const unsigned longs defined in
1251 // xpcom/system/nsIXULRuntime.idl.
1252 #define GECKO_PROCESS_TYPE(enum_value, enum_name, string_name, proc_typename, \
1253 process_bin_type, procinfo_typename, \
1254 webidl_typename, allcaps_name) \
1255 static_assert(nsIXULRuntime::PROCESS_TYPE_##allcaps_name == \
1256 static_cast<int>(GeckoProcessType_##enum_name), \
1257 "GeckoProcessType in nsXULAppAPI.h not synchronized with " \
1258 "nsIXULRuntime.idl");
1259 #include "mozilla/GeckoProcessTypes.h"
1260 #undef GECKO_PROCESS_TYPE
1262 // .. and ensure that that is all of them:
1263 static_assert(GeckoProcessType_Utility + 1 == GeckoProcessType_End,
1264 "Did not find the final GeckoProcessType");
1266 NS_IMETHODIMP
1267 nsXULAppInfo::GetProcessType(uint32_t* aResult) {
1268 NS_ENSURE_ARG_POINTER(aResult);
1269 *aResult = XRE_GetProcessType();
1270 return NS_OK;
1273 NS_IMETHODIMP
1274 nsXULAppInfo::GetProcessID(uint32_t* aResult) {
1275 #ifdef XP_WIN
1276 *aResult = GetCurrentProcessId();
1277 #else
1278 *aResult = getpid();
1279 #endif
1280 return NS_OK;
1283 NS_IMETHODIMP
1284 nsXULAppInfo::GetUniqueProcessID(uint64_t* aResult) {
1285 if (XRE_IsContentProcess()) {
1286 ContentChild* cc = ContentChild::GetSingleton();
1287 *aResult = cc->GetID();
1288 } else {
1289 *aResult = 0;
1291 return NS_OK;
1294 NS_IMETHODIMP
1295 nsXULAppInfo::GetRemoteType(nsACString& aRemoteType) {
1296 if (XRE_IsContentProcess()) {
1297 aRemoteType = ContentChild::GetSingleton()->GetRemoteType();
1298 } else {
1299 aRemoteType = NOT_REMOTE_TYPE;
1302 return NS_OK;
1305 static nsCString gLastAppVersion;
1306 static nsCString gLastAppBuildID;
1308 NS_IMETHODIMP
1309 nsXULAppInfo::GetLastAppVersion(nsACString& aResult) {
1310 if (XRE_IsContentProcess()) {
1311 return NS_ERROR_NOT_AVAILABLE;
1314 if (!gLastAppVersion.IsVoid() && gLastAppVersion.IsEmpty()) {
1315 NS_WARNING("Attempt to retrieve lastAppVersion before it has been set.");
1316 return NS_ERROR_NOT_AVAILABLE;
1319 aResult.Assign(gLastAppVersion);
1320 return NS_OK;
1323 NS_IMETHODIMP
1324 nsXULAppInfo::GetLastAppBuildID(nsACString& aResult) {
1325 if (XRE_IsContentProcess()) {
1326 return NS_ERROR_NOT_AVAILABLE;
1329 if (!gLastAppBuildID.IsVoid() && gLastAppBuildID.IsEmpty()) {
1330 NS_WARNING("Attempt to retrieve lastAppBuildID before it has been set.");
1331 return NS_ERROR_NOT_AVAILABLE;
1334 aResult.Assign(gLastAppBuildID);
1335 return NS_OK;
1338 NS_IMETHODIMP
1339 nsXULAppInfo::GetFissionAutostart(bool* aResult) {
1340 *aResult = FissionAutostart();
1341 return NS_OK;
1344 NS_IMETHODIMP
1345 nsXULAppInfo::GetWin32kExperimentStatus(ExperimentStatus* aResult) {
1346 if (!XRE_IsParentProcess()) {
1347 return NS_ERROR_NOT_AVAILABLE;
1350 EnsureWin32kInitialized();
1351 *aResult = gWin32kExperimentStatus;
1352 return NS_OK;
1355 NS_IMETHODIMP
1356 nsXULAppInfo::GetWin32kLiveStatusTestingOnly(
1357 nsIXULRuntime::ContentWin32kLockdownState* aResult) {
1358 if (!XRE_IsParentProcess()) {
1359 return NS_ERROR_NOT_AVAILABLE;
1362 EnsureWin32kInitialized();
1363 *aResult = GetLiveWin32kLockdownState();
1364 return NS_OK;
1367 NS_IMETHODIMP
1368 nsXULAppInfo::GetWin32kSessionStatus(
1369 nsIXULRuntime::ContentWin32kLockdownState* aResult) {
1370 if (!XRE_IsParentProcess()) {
1371 return NS_ERROR_NOT_AVAILABLE;
1374 EnsureWin32kInitialized();
1375 *aResult = gWin32kStatus;
1376 return NS_OK;
1379 NS_IMETHODIMP
1380 nsXULAppInfo::GetFissionDecisionStatus(FissionDecisionStatus* aResult) {
1381 if (!XRE_IsParentProcess()) {
1382 return NS_ERROR_NOT_AVAILABLE;
1385 EnsureFissionAutostartInitialized();
1387 MOZ_ASSERT(gFissionDecisionStatus != eFissionStatusUnknown);
1388 *aResult = gFissionDecisionStatus;
1389 return NS_OK;
1392 NS_IMETHODIMP
1393 nsXULAppInfo::GetFissionDecisionStatusString(nsACString& aResult) {
1394 if (!XRE_IsParentProcess()) {
1395 return NS_ERROR_NOT_AVAILABLE;
1398 EnsureFissionAutostartInitialized();
1399 switch (gFissionDecisionStatus) {
1400 case eFissionExperimentControl:
1401 aResult = "experimentControl";
1402 break;
1403 case eFissionExperimentTreatment:
1404 aResult = "experimentTreatment";
1405 break;
1406 case eFissionDisabledByE10sEnv:
1407 aResult = "disabledByE10sEnv";
1408 break;
1409 case eFissionEnabledByEnv:
1410 aResult = "enabledByEnv";
1411 break;
1412 case eFissionDisabledByEnv:
1413 aResult = "disabledByEnv";
1414 break;
1415 case eFissionEnabledByDefault:
1416 aResult = "enabledByDefault";
1417 break;
1418 case eFissionDisabledByDefault:
1419 aResult = "disabledByDefault";
1420 break;
1421 case eFissionEnabledByUserPref:
1422 aResult = "enabledByUserPref";
1423 break;
1424 case eFissionDisabledByUserPref:
1425 aResult = "disabledByUserPref";
1426 break;
1427 case eFissionDisabledByE10sOther:
1428 aResult = "disabledByE10sOther";
1429 break;
1430 case eFissionEnabledByRollout:
1431 aResult = "enabledByRollout";
1432 break;
1433 default:
1434 MOZ_ASSERT_UNREACHABLE("Unexpected enum value");
1436 return NS_OK;
1439 NS_IMETHODIMP
1440 nsXULAppInfo::GetSessionHistoryInParent(bool* aResult) {
1441 *aResult = SessionHistoryInParent();
1442 return NS_OK;
1445 NS_IMETHODIMP
1446 nsXULAppInfo::GetBrowserTabsRemoteAutostart(bool* aResult) {
1447 *aResult = BrowserTabsRemoteAutostart();
1448 return NS_OK;
1451 NS_IMETHODIMP
1452 nsXULAppInfo::GetMaxWebProcessCount(uint32_t* aResult) {
1453 *aResult = mozilla::GetMaxWebProcessCount();
1454 return NS_OK;
1457 NS_IMETHODIMP
1458 nsXULAppInfo::GetAccessibilityEnabled(bool* aResult) {
1459 #ifdef ACCESSIBILITY
1460 *aResult = GetAccService() != nullptr;
1461 #else
1462 *aResult = false;
1463 #endif
1464 return NS_OK;
1467 NS_IMETHODIMP
1468 nsXULAppInfo::GetAccessibilityInstantiator(nsAString& aInstantiator) {
1469 #if defined(ACCESSIBILITY) && defined(XP_WIN)
1470 if (!GetAccService()) {
1471 aInstantiator.Truncate();
1472 return NS_OK;
1474 nsAutoString ipClientInfo;
1475 a11y::Compatibility::GetHumanReadableConsumersStr(ipClientInfo);
1476 aInstantiator.Append(ipClientInfo);
1477 aInstantiator.AppendLiteral("|");
1479 nsCOMPtr<nsIFile> oopClientExe;
1480 if (a11y::GetInstantiator(getter_AddRefs(oopClientExe))) {
1481 nsAutoString oopClientInfo;
1482 if (NS_SUCCEEDED(oopClientExe->GetPath(oopClientInfo))) {
1483 aInstantiator.Append(oopClientInfo);
1486 #else
1487 aInstantiator.Truncate();
1488 #endif
1489 return NS_OK;
1492 NS_IMETHODIMP
1493 nsXULAppInfo::GetIs64Bit(bool* aResult) {
1494 #ifdef HAVE_64BIT_BUILD
1495 *aResult = true;
1496 #else
1497 *aResult = false;
1498 #endif
1499 return NS_OK;
1502 NS_IMETHODIMP
1503 nsXULAppInfo::GetIsTextRecognitionSupported(bool* aResult) {
1504 *aResult = widget::TextRecognition::IsSupported();
1505 return NS_OK;
1508 NS_IMETHODIMP
1509 nsXULAppInfo::EnsureContentProcess() {
1510 if (!XRE_IsParentProcess()) return NS_ERROR_NOT_AVAILABLE;
1512 RefPtr<ContentParent> unused =
1513 ContentParent::GetNewOrUsedBrowserProcess(DEFAULT_REMOTE_TYPE);
1514 return NS_OK;
1517 NS_IMETHODIMP
1518 nsXULAppInfo::InvalidateCachesOnRestart() {
1519 nsCOMPtr<nsIFile> file;
1520 nsresult rv =
1521 NS_GetSpecialDirectory(NS_APP_PROFILE_DIR_STARTUP, getter_AddRefs(file));
1522 if (NS_FAILED(rv)) return rv;
1523 if (!file) return NS_ERROR_NOT_AVAILABLE;
1525 file->AppendNative(FILE_COMPATIBILITY_INFO);
1527 nsINIParser parser;
1528 rv = parser.Init(file);
1529 if (NS_FAILED(rv)) {
1530 // This fails if compatibility.ini is not there, so we'll
1531 // flush the caches on the next restart anyways.
1532 return NS_OK;
1535 nsAutoCString buf;
1536 rv = parser.GetString("Compatibility", "InvalidateCaches", buf);
1538 if (NS_FAILED(rv)) {
1539 PRFileDesc* fd;
1540 rv = file->OpenNSPRFileDesc(PR_RDWR | PR_APPEND, 0600, &fd);
1541 if (NS_FAILED(rv)) {
1542 NS_ERROR("could not create output stream");
1543 return NS_ERROR_NOT_AVAILABLE;
1545 static const char kInvalidationHeader[] =
1546 NS_LINEBREAK "InvalidateCaches=1" NS_LINEBREAK;
1547 PR_Write(fd, kInvalidationHeader, sizeof(kInvalidationHeader) - 1);
1548 PR_Close(fd);
1550 return NS_OK;
1553 NS_IMETHODIMP
1554 nsXULAppInfo::GetReplacedLockTime(PRTime* aReplacedLockTime) {
1555 if (!gProfileLock) return NS_ERROR_NOT_AVAILABLE;
1556 gProfileLock->GetReplacedLockTime(aReplacedLockTime);
1557 return NS_OK;
1560 NS_IMETHODIMP
1561 nsXULAppInfo::GetDefaultUpdateChannel(nsACString& aResult) {
1562 aResult.AssignLiteral(MOZ_STRINGIFY(MOZ_UPDATE_CHANNEL));
1563 return NS_OK;
1566 NS_IMETHODIMP
1567 nsXULAppInfo::GetDistributionID(nsACString& aResult) {
1568 aResult.AssignLiteral(MOZ_DISTRIBUTION_ID);
1569 return NS_OK;
1572 NS_IMETHODIMP
1573 nsXULAppInfo::GetWindowsDLLBlocklistStatus(bool* aResult) {
1574 #if defined(HAS_DLL_BLOCKLIST)
1575 *aResult = DllBlocklist_CheckStatus();
1576 #else
1577 *aResult = false;
1578 #endif
1579 return NS_OK;
1582 NS_IMETHODIMP
1583 nsXULAppInfo::GetRestartedByOS(bool* aResult) {
1584 *aResult = gRestartedByOS;
1585 return NS_OK;
1588 NS_IMETHODIMP
1589 nsXULAppInfo::GetChromeColorSchemeIsDark(bool* aResult) {
1590 PreferenceSheet::EnsureInitialized();
1591 *aResult = PreferenceSheet::ColorSchemeForChrome() == ColorScheme::Dark;
1592 return NS_OK;
1595 NS_IMETHODIMP
1596 nsXULAppInfo::GetContentThemeDerivedColorSchemeIsDark(bool* aResult) {
1597 *aResult =
1598 PreferenceSheet::ThemeDerivedColorSchemeForContent() == ColorScheme::Dark;
1599 return NS_OK;
1602 NS_IMETHODIMP
1603 nsXULAppInfo::GetPrefersReducedMotion(bool* aResult) {
1604 *aResult =
1605 LookAndFeel::GetInt(LookAndFeel::IntID::PrefersReducedMotion, 0) == 1;
1606 return NS_OK;
1609 NS_IMETHODIMP
1610 nsXULAppInfo::GetDrawInTitlebar(bool* aResult) {
1611 *aResult = LookAndFeel::DrawInTitlebar();
1612 return NS_OK;
1615 NS_IMETHODIMP
1616 nsXULAppInfo::GetDesktopEnvironment(nsACString& aDesktopEnvironment) {
1617 #ifdef MOZ_WIDGET_GTK
1618 aDesktopEnvironment.Assign(GetDesktopEnvironmentIdentifier());
1619 #endif
1620 return NS_OK;
1623 NS_IMETHODIMP
1624 nsXULAppInfo::GetIsWayland(bool* aResult) {
1625 #ifdef MOZ_WIDGET_GTK
1626 *aResult = GdkIsWaylandDisplay();
1627 #else
1628 *aResult = false;
1629 #endif
1630 return NS_OK;
1633 NS_IMETHODIMP
1634 nsXULAppInfo::GetProcessStartupShortcut(nsAString& aShortcut) {
1635 #if defined(XP_WIN)
1636 if (XRE_IsParentProcess()) {
1637 aShortcut.Assign(gProcessStartupShortcut);
1638 return NS_OK;
1640 #endif
1641 return NS_ERROR_NOT_AVAILABLE;
1644 #if defined(XP_WIN) && defined(MOZ_LAUNCHER_PROCESS)
1645 // Forward declaration
1646 void SetupLauncherProcessPref();
1648 static Maybe<LauncherRegistryInfo::EnabledState> gLauncherProcessState;
1649 #endif // defined(XP_WIN) && defined(MOZ_LAUNCHER_PROCESS)
1651 NS_IMETHODIMP
1652 nsXULAppInfo::GetLauncherProcessState(uint32_t* aResult) {
1653 #if defined(XP_WIN) && defined(MOZ_LAUNCHER_PROCESS)
1654 SetupLauncherProcessPref();
1656 if (!gLauncherProcessState) {
1657 return NS_ERROR_UNEXPECTED;
1660 *aResult = static_cast<uint32_t>(gLauncherProcessState.value());
1661 return NS_OK;
1662 #else
1663 return NS_ERROR_NOT_AVAILABLE;
1664 #endif
1667 #ifdef XP_WIN
1668 NS_IMETHODIMP
1669 nsXULAppInfo::GetUserCanElevate(bool* aUserCanElevate) {
1670 HANDLE rawToken;
1671 if (!::OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY, &rawToken)) {
1672 *aUserCanElevate = false;
1673 return NS_OK;
1676 nsAutoHandle token(rawToken);
1677 LauncherResult<TOKEN_ELEVATION_TYPE> elevationType = GetElevationType(token);
1678 if (elevationType.isErr()) {
1679 *aUserCanElevate = false;
1680 return NS_OK;
1683 // The possible values returned for elevationType and their meanings are:
1684 // TokenElevationTypeDefault: The token does not have a linked token
1685 // (e.g. UAC disabled or a standard user, so they can't be elevated)
1686 // TokenElevationTypeFull: The token is linked to an elevated token
1687 // (e.g. UAC is enabled and the user is already elevated so they can't
1688 // be elevated again)
1689 // TokenElevationTypeLimited: The token is linked to a limited token
1690 // (e.g. UAC is enabled and the user is not elevated, so they can be
1691 // elevated)
1692 *aUserCanElevate = (elevationType.inspect() == TokenElevationTypeLimited);
1693 return NS_OK;
1695 #endif
1697 NS_IMETHODIMP
1698 nsXULAppInfo::GetCrashReporterEnabled(bool* aEnabled) {
1699 *aEnabled = CrashReporter::GetEnabled();
1700 return NS_OK;
1703 NS_IMETHODIMP
1704 nsXULAppInfo::SetEnabled(bool aEnabled) {
1705 if (aEnabled) {
1706 if (CrashReporter::GetEnabled()) {
1707 // no point in erroring for double-enabling
1708 return NS_OK;
1711 nsCOMPtr<nsIFile> greBinDir;
1712 NS_GetSpecialDirectory(NS_GRE_BIN_DIR, getter_AddRefs(greBinDir));
1713 if (!greBinDir) {
1714 return NS_ERROR_FAILURE;
1717 nsCOMPtr<nsIFile> xreBinDirectory = greBinDir;
1718 if (!xreBinDirectory) {
1719 return NS_ERROR_FAILURE;
1722 return CrashReporter::SetExceptionHandler(xreBinDirectory, true);
1725 if (!CrashReporter::GetEnabled()) {
1726 // no point in erroring for double-disabling
1727 return NS_OK;
1730 return CrashReporter::UnsetExceptionHandler();
1733 NS_IMETHODIMP
1734 nsXULAppInfo::GetServerURL(nsIURL** aServerURL) {
1735 NS_ENSURE_ARG_POINTER(aServerURL);
1736 if (!CrashReporter::GetEnabled()) return NS_ERROR_NOT_INITIALIZED;
1738 nsAutoCString data;
1739 if (!CrashReporter::GetServerURL(data)) {
1740 return NS_ERROR_FAILURE;
1742 nsCOMPtr<nsIURI> uri;
1743 NS_NewURI(getter_AddRefs(uri), data);
1744 if (!uri) return NS_ERROR_FAILURE;
1746 nsCOMPtr<nsIURL> url;
1747 url = do_QueryInterface(uri);
1748 NS_ADDREF(*aServerURL = url);
1750 return NS_OK;
1753 NS_IMETHODIMP
1754 nsXULAppInfo::SetServerURL(nsIURL* aServerURL) {
1755 // Only allow https or http URLs
1756 if (!aServerURL->SchemeIs("http") && !aServerURL->SchemeIs("https")) {
1757 return NS_ERROR_INVALID_ARG;
1760 nsAutoCString spec;
1761 nsresult rv = aServerURL->GetSpec(spec);
1762 NS_ENSURE_SUCCESS(rv, rv);
1764 return CrashReporter::SetServerURL(spec);
1767 NS_IMETHODIMP
1768 nsXULAppInfo::GetMinidumpPath(nsIFile** aMinidumpPath) {
1769 if (!CrashReporter::GetEnabled()) return NS_ERROR_NOT_INITIALIZED;
1771 nsAutoString path;
1772 if (!CrashReporter::GetMinidumpPath(path)) return NS_ERROR_FAILURE;
1774 nsresult rv = NS_NewLocalFile(path, false, aMinidumpPath);
1775 NS_ENSURE_SUCCESS(rv, rv);
1776 return NS_OK;
1779 NS_IMETHODIMP
1780 nsXULAppInfo::SetMinidumpPath(nsIFile* aMinidumpPath) {
1781 nsAutoString path;
1782 nsresult rv = aMinidumpPath->GetPath(path);
1783 NS_ENSURE_SUCCESS(rv, rv);
1784 return CrashReporter::SetMinidumpPath(path);
1787 NS_IMETHODIMP
1788 nsXULAppInfo::GetMinidumpForID(const nsAString& aId, nsIFile** aMinidump) {
1789 if (!CrashReporter::GetMinidumpForID(aId, aMinidump)) {
1790 return NS_ERROR_FILE_NOT_FOUND;
1793 return NS_OK;
1796 NS_IMETHODIMP
1797 nsXULAppInfo::GetExtraFileForID(const nsAString& aId, nsIFile** aExtraFile) {
1798 if (!CrashReporter::GetExtraFileForID(aId, aExtraFile)) {
1799 return NS_ERROR_FILE_NOT_FOUND;
1802 return NS_OK;
1805 NS_IMETHODIMP
1806 nsXULAppInfo::AnnotateCrashReport(const nsACString& key,
1807 const nsACString& data) {
1808 CrashReporter::Annotation annotation;
1810 if (!AnnotationFromString(annotation, PromiseFlatCString(key).get())) {
1811 return NS_ERROR_INVALID_ARG;
1814 return CrashReporter::AnnotateCrashReport(annotation, data);
1817 NS_IMETHODIMP
1818 nsXULAppInfo::RemoveCrashReportAnnotation(const nsACString& key) {
1819 CrashReporter::Annotation annotation;
1821 if (!AnnotationFromString(annotation, PromiseFlatCString(key).get())) {
1822 return NS_ERROR_INVALID_ARG;
1825 return CrashReporter::RemoveCrashReportAnnotation(annotation);
1828 NS_IMETHODIMP
1829 nsXULAppInfo::IsAnnotationAllowlistedForPing(const nsACString& aValue,
1830 bool* aIsAllowlisted) {
1831 CrashReporter::Annotation annotation;
1833 if (!AnnotationFromString(annotation, PromiseFlatCString(aValue).get())) {
1834 return NS_ERROR_INVALID_ARG;
1837 *aIsAllowlisted = CrashReporter::IsAnnotationAllowlistedForPing(annotation);
1839 return NS_OK;
1842 NS_IMETHODIMP
1843 nsXULAppInfo::AppendAppNotesToCrashReport(const nsACString& data) {
1844 return CrashReporter::AppendAppNotesToCrashReport(data);
1847 NS_IMETHODIMP
1848 nsXULAppInfo::RegisterAppMemory(uint64_t pointer, uint64_t len) {
1849 return CrashReporter::RegisterAppMemory((void*)pointer, len);
1852 NS_IMETHODIMP
1853 nsXULAppInfo::WriteMinidumpForException(void* aExceptionInfo) {
1854 #ifdef XP_WIN
1855 return CrashReporter::WriteMinidumpForException(
1856 static_cast<EXCEPTION_POINTERS*>(aExceptionInfo));
1857 #else
1858 return NS_ERROR_NOT_IMPLEMENTED;
1859 #endif
1862 NS_IMETHODIMP
1863 nsXULAppInfo::AppendObjCExceptionInfoToAppNotes(void* aException) {
1864 #ifdef XP_MACOSX
1865 return CrashReporter::AppendObjCExceptionInfoToAppNotes(aException);
1866 #else
1867 return NS_ERROR_NOT_IMPLEMENTED;
1868 #endif
1871 NS_IMETHODIMP
1872 nsXULAppInfo::GetSubmitReports(bool* aEnabled) {
1873 return CrashReporter::GetSubmitReports(aEnabled);
1876 NS_IMETHODIMP
1877 nsXULAppInfo::SetSubmitReports(bool aEnabled) {
1878 return CrashReporter::SetSubmitReports(aEnabled);
1881 NS_IMETHODIMP
1882 nsXULAppInfo::UpdateCrashEventsDir() {
1883 CrashReporter::UpdateCrashEventsDir();
1884 return NS_OK;
1887 NS_IMETHODIMP
1888 nsXULAppInfo::SaveMemoryReport() {
1889 if (!CrashReporter::GetEnabled()) {
1890 return NS_ERROR_NOT_INITIALIZED;
1892 nsCOMPtr<nsIFile> file;
1893 nsresult rv = CrashReporter::GetDefaultMemoryReportFile(getter_AddRefs(file));
1894 if (NS_WARN_IF(NS_FAILED(rv))) {
1895 return rv;
1898 nsString path;
1899 file->GetPath(path);
1901 nsCOMPtr<nsIMemoryInfoDumper> dumper =
1902 do_GetService("@mozilla.org/memory-info-dumper;1");
1903 if (NS_WARN_IF(!dumper)) {
1904 return NS_ERROR_UNEXPECTED;
1907 rv = dumper->DumpMemoryReportsToNamedFile(
1908 path, this, file, true /* anonymize */, false /* minimizeMemoryUsage */);
1909 if (NS_WARN_IF(NS_FAILED(rv))) {
1910 return rv;
1912 return NS_OK;
1915 // This method is from nsIFInishDumpingCallback.
1916 NS_IMETHODIMP
1917 nsXULAppInfo::Callback(nsISupports* aData) {
1918 nsCOMPtr<nsIFile> file = do_QueryInterface(aData);
1919 MOZ_ASSERT(file);
1921 CrashReporter::SetMemoryReportFile(file);
1922 return NS_OK;
1925 static const nsXULAppInfo kAppInfo;
1926 namespace mozilla {
1927 nsresult AppInfoConstructor(REFNSIID aIID, void** aResult) {
1928 return const_cast<nsXULAppInfo*>(&kAppInfo)->QueryInterface(aIID, aResult);
1930 } // namespace mozilla
1932 bool gLogConsoleErrors = false;
1934 #define NS_ENSURE_TRUE_LOG(x, ret) \
1935 PR_BEGIN_MACRO \
1936 if (MOZ_UNLIKELY(!(x))) { \
1937 NS_WARNING("NS_ENSURE_TRUE(" #x ") failed"); \
1938 gLogConsoleErrors = true; \
1939 return ret; \
1941 PR_END_MACRO
1943 #define NS_ENSURE_SUCCESS_LOG(res, ret) \
1944 NS_ENSURE_TRUE_LOG(NS_SUCCEEDED(res), ret)
1947 * Because we're starting/stopping XPCOM several times in different scenarios,
1948 * this class is a stack-based critter that makes sure that XPCOM is shut down
1949 * during early returns.
1952 class ScopedXPCOMStartup {
1953 public:
1954 ScopedXPCOMStartup() : mServiceManager(nullptr) {}
1955 ~ScopedXPCOMStartup();
1957 nsresult Initialize(bool aInitJSContext = true);
1958 nsresult SetWindowCreator(nsINativeAppSupport* native);
1960 private:
1961 nsIServiceManager* mServiceManager;
1962 static nsINativeAppSupport* gNativeAppSupport;
1964 friend already_AddRefed<nsINativeAppSupport> NS_GetNativeAppSupport();
1967 ScopedXPCOMStartup::~ScopedXPCOMStartup() {
1968 NS_IF_RELEASE(gNativeAppSupport);
1970 if (mServiceManager) {
1971 #ifdef XP_MACOSX
1972 // On OS X, we need a pool to catch cocoa objects that are autoreleased
1973 // during teardown.
1974 mozilla::MacAutoreleasePool pool;
1975 #endif
1977 nsCOMPtr<nsIAppStartup> appStartup(components::AppStartup::Service());
1978 if (appStartup) appStartup->DestroyHiddenWindow();
1980 gDirServiceProvider->DoShutdown();
1981 PROFILER_MARKER_UNTYPED("Shutdown early", OTHER);
1983 WriteConsoleLog();
1985 NS_ShutdownXPCOM(mServiceManager);
1986 mServiceManager = nullptr;
1990 nsresult ScopedXPCOMStartup::Initialize(bool aInitJSContext) {
1991 NS_ASSERTION(gDirServiceProvider, "Should not get here!");
1993 nsresult rv;
1995 rv = NS_InitXPCOM(&mServiceManager, gDirServiceProvider->GetAppDir(),
1996 gDirServiceProvider, aInitJSContext);
1997 if (NS_FAILED(rv)) {
1998 NS_ERROR("Couldn't start xpcom!");
1999 mServiceManager = nullptr;
2000 } else {
2001 #ifdef DEBUG
2002 nsCOMPtr<nsIComponentRegistrar> reg = do_QueryInterface(mServiceManager);
2003 NS_ASSERTION(reg, "Service Manager doesn't QI to Registrar.");
2004 #endif
2007 return rv;
2011 * This is a little factory class that serves as a singleton-service-factory
2012 * for the nativeappsupport object.
2014 class nsSingletonFactory final : public nsIFactory {
2015 public:
2016 NS_DECL_ISUPPORTS
2017 NS_DECL_NSIFACTORY
2019 explicit nsSingletonFactory(nsISupports* aSingleton);
2021 private:
2022 ~nsSingletonFactory() = default;
2023 nsCOMPtr<nsISupports> mSingleton;
2026 nsSingletonFactory::nsSingletonFactory(nsISupports* aSingleton)
2027 : mSingleton(aSingleton) {
2028 NS_ASSERTION(mSingleton, "Singleton was null!");
2031 NS_IMPL_ISUPPORTS(nsSingletonFactory, nsIFactory)
2033 NS_IMETHODIMP
2034 nsSingletonFactory::CreateInstance(const nsIID& aIID, void** aResult) {
2035 return mSingleton->QueryInterface(aIID, aResult);
2039 * Set our windowcreator on the WindowWatcher service.
2041 nsresult ScopedXPCOMStartup::SetWindowCreator(nsINativeAppSupport* native) {
2042 nsresult rv;
2044 NS_IF_ADDREF(gNativeAppSupport = native);
2046 nsCOMPtr<nsIWindowCreator> creator(components::AppStartup::Service());
2047 if (!creator) return NS_ERROR_UNEXPECTED;
2049 nsCOMPtr<nsIWindowWatcher> wwatch(
2050 do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv));
2051 NS_ENSURE_SUCCESS(rv, rv);
2053 return wwatch->SetWindowCreator(creator);
2056 /* static */ already_AddRefed<nsINativeAppSupport> NS_GetNativeAppSupport() {
2057 if (!ScopedXPCOMStartup::gNativeAppSupport) {
2058 return nullptr;
2061 return do_AddRef(ScopedXPCOMStartup::gNativeAppSupport);
2064 nsINativeAppSupport* ScopedXPCOMStartup::gNativeAppSupport;
2066 static void DumpArbitraryHelp() {
2067 nsresult rv;
2069 ScopedLogging log;
2072 ScopedXPCOMStartup xpcom;
2073 xpcom.Initialize();
2075 nsCOMPtr<nsICommandLineRunner> cmdline(new nsCommandLine());
2077 nsCString text;
2078 rv = cmdline->GetHelpText(text);
2079 if (NS_SUCCEEDED(rv)) printf("%s", text.get());
2083 // English text needs to go into a dtd file.
2084 // But when this is called we have no components etc. These strings must either
2085 // be here, or in a native resource file.
2086 static void DumpHelp() {
2087 printf(
2088 "Usage: %s [ options ... ] [URL]\n"
2089 " where options include:\n\n",
2090 gArgv[0]);
2092 #ifdef MOZ_X11
2093 printf(
2094 "X11 options\n"
2095 " --display=DISPLAY X display to use\n"
2096 " --sync Make X calls synchronous\n");
2097 #endif
2098 #ifdef XP_UNIX
2099 printf(
2100 " --g-fatal-warnings Make all warnings fatal\n"
2101 "\n%s options\n",
2102 (const char*)gAppData->name);
2103 #endif
2105 printf(
2106 " -h or --help Print this message.\n"
2107 " -v or --version Print %s version.\n"
2108 " --full-version Print %s version, build and platform build ids.\n"
2109 " -P <profile> Start with <profile>.\n"
2110 " --profile <path> Start with profile at <path>.\n"
2111 " --migration Start with migration wizard.\n"
2112 " --ProfileManager Start with ProfileManager.\n"
2113 #ifdef MOZ_HAS_REMOTE
2114 " --no-remote Do not accept or send remote commands; implies\n"
2115 " --new-instance.\n"
2116 " --new-instance Open new instance, not a new window in running "
2117 "instance.\n"
2118 #endif
2119 " --safe-mode Disables extensions and themes for this session.\n"
2120 #ifdef MOZ_BLOCK_PROFILE_DOWNGRADE
2121 " --allow-downgrade Allows downgrading a profile.\n"
2122 #endif
2123 " --MOZ_LOG=<modules> Treated as MOZ_LOG=<modules> environment "
2124 "variable,\n"
2125 " overrides it.\n"
2126 " --MOZ_LOG_FILE=<file> Treated as MOZ_LOG_FILE=<file> environment "
2127 "variable,\n"
2128 " overrides it. If MOZ_LOG_FILE is not specified as "
2129 "an\n"
2130 " argument or as an environment variable, logging "
2131 "will be\n"
2132 " written to stdout.\n",
2133 (const char*)gAppData->name, (const char*)gAppData->name);
2135 #if defined(XP_WIN)
2136 printf(" --console Start %s with a debugging console.\n",
2137 (const char*)gAppData->name);
2138 #endif
2140 #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) || defined(XP_MACOSX)
2141 printf(" --headless Run without a GUI.\n");
2142 #endif
2144 // this works, but only after the components have registered. so if you drop
2145 // in a new command line handler, --help won't not until the second run. out
2146 // of the bug, because we ship a component.reg file, it works correctly.
2147 DumpArbitraryHelp();
2150 static inline void DumpVersion() {
2151 if (gAppData->vendor && *gAppData->vendor) {
2152 printf("%s ", (const char*)gAppData->vendor);
2154 printf("%s ", (const char*)gAppData->name);
2156 // Use the displayed version
2157 // For example, for beta, we would display 42.0b2 instead of 42.0
2158 printf("%s", MOZ_STRINGIFY(MOZ_APP_VERSION_DISPLAY));
2160 if (gAppData->copyright && *gAppData->copyright) {
2161 printf(", %s", (const char*)gAppData->copyright);
2163 printf("\n");
2166 static inline void DumpFullVersion() {
2167 if (gAppData->vendor && *gAppData->vendor) {
2168 printf("%s ", (const char*)gAppData->vendor);
2170 printf("%s ", (const char*)gAppData->name);
2172 // Use the displayed version
2173 // For example, for beta, we would display 42.0b2 instead of 42.0
2174 printf("%s ", MOZ_STRINGIFY(MOZ_APP_VERSION_DISPLAY));
2176 printf("%s ", (const char*)gAppData->buildID);
2177 printf("%s ", (const char*)PlatformBuildID());
2178 if (gAppData->copyright && *gAppData->copyright) {
2179 printf(", %s", (const char*)gAppData->copyright);
2181 printf("\n");
2184 void XRE_InitOmnijar(nsIFile* greOmni, nsIFile* appOmni) {
2185 mozilla::Omnijar::Init(greOmni, appOmni);
2188 nsresult XRE_GetBinaryPath(nsIFile** aResult) {
2189 return mozilla::BinaryPath::GetFile(aResult);
2192 #ifdef XP_WIN
2193 # include "nsWindowsRestart.cpp"
2194 # include <shellapi.h>
2196 typedef BOOL(WINAPI* SetProcessDEPPolicyFunc)(DWORD dwFlags);
2198 static void RegisterApplicationRestartChanged(const char* aPref, void* aData) {
2199 DWORD cchCmdLine = 0;
2200 HRESULT rc = ::GetApplicationRestartSettings(::GetCurrentProcess(), nullptr,
2201 &cchCmdLine, nullptr);
2202 bool wasRegistered = false;
2203 if (rc == S_OK) {
2204 wasRegistered = true;
2207 if (Preferences::GetBool(PREF_WIN_REGISTER_APPLICATION_RESTART, false) &&
2208 !wasRegistered) {
2209 // Make the command line to use when restarting.
2210 // Excludes argv[0] because RegisterApplicationRestart adds the
2211 // executable name, replace that temporarily with -os-restarted
2212 char* exeName = gRestartArgv[0];
2213 gRestartArgv[0] = const_cast<char*>("-os-restarted");
2214 wchar_t** restartArgvConverted =
2215 AllocConvertUTF8toUTF16Strings(gRestartArgc, gRestartArgv);
2216 gRestartArgv[0] = exeName;
2218 mozilla::UniquePtr<wchar_t[]> restartCommandLine;
2219 if (restartArgvConverted) {
2220 restartCommandLine =
2221 mozilla::MakeCommandLine(gRestartArgc, restartArgvConverted);
2222 FreeAllocStrings(gRestartArgc, restartArgvConverted);
2225 if (restartCommandLine) {
2226 // Flags RESTART_NO_PATCH and RESTART_NO_REBOOT are not set, so we
2227 // should be restarted if terminated by an update or restart.
2228 ::RegisterApplicationRestart(restartCommandLine.get(),
2229 RESTART_NO_CRASH | RESTART_NO_HANG);
2231 } else if (wasRegistered) {
2232 ::UnregisterApplicationRestart();
2236 static void OnAlteredPrefetchPrefChanged(const char* aPref, void* aData) {
2237 int32_t prefVal = Preferences::GetInt(PREF_WIN_ALTERED_DLL_PREFETCH, 0);
2239 mozilla::DllPrefetchExperimentRegistryInfo prefetchRegInfo;
2240 mozilla::DebugOnly<mozilla::Result<Ok, nsresult>> reflectResult =
2241 prefetchRegInfo.ReflectPrefToRegistry(prefVal);
2243 MOZ_ASSERT(reflectResult.value.isOk());
2246 static void SetupAlteredPrefetchPref() {
2247 mozilla::DllPrefetchExperimentRegistryInfo prefetchRegInfo;
2249 mozilla::DebugOnly<mozilla::Result<Ok, nsresult>> reflectResult =
2250 prefetchRegInfo.ReflectPrefToRegistry(
2251 Preferences::GetInt(PREF_WIN_ALTERED_DLL_PREFETCH, 0));
2252 MOZ_ASSERT(reflectResult.value.isOk());
2254 Preferences::RegisterCallback(&OnAlteredPrefetchPrefChanged,
2255 PREF_WIN_ALTERED_DLL_PREFETCH);
2258 static void ReflectSkeletonUIPrefToRegistry(const char* aPref, void* aData) {
2259 Unused << aPref;
2260 Unused << aData;
2262 bool shouldBeEnabled =
2263 Preferences::GetBool(kPrefPreXulSkeletonUI, false) &&
2264 Preferences::GetBool(kPrefBrowserStartupBlankWindow, false) &&
2265 LookAndFeel::DrawInTitlebar();
2266 if (shouldBeEnabled && Preferences::HasUserValue(kPrefThemeId)) {
2267 nsCString themeId;
2268 Preferences::GetCString(kPrefThemeId, themeId);
2269 if (themeId.EqualsLiteral("default-theme@mozilla.org")) {
2270 Unused << SetPreXULSkeletonUIThemeId(ThemeMode::Default);
2271 } else if (themeId.EqualsLiteral("firefox-compact-dark@mozilla.org")) {
2272 Unused << SetPreXULSkeletonUIThemeId(ThemeMode::Dark);
2273 } else if (themeId.EqualsLiteral("firefox-compact-light@mozilla.org")) {
2274 Unused << SetPreXULSkeletonUIThemeId(ThemeMode::Light);
2275 } else {
2276 shouldBeEnabled = false;
2278 } else if (shouldBeEnabled) {
2279 Unused << SetPreXULSkeletonUIThemeId(ThemeMode::Default);
2282 if (GetPreXULSkeletonUIEnabled() != shouldBeEnabled) {
2283 Unused << SetPreXULSkeletonUIEnabledIfAllowed(shouldBeEnabled);
2287 static void SetupSkeletonUIPrefs() {
2288 ReflectSkeletonUIPrefToRegistry(nullptr, nullptr);
2289 Preferences::RegisterCallback(&ReflectSkeletonUIPrefToRegistry,
2290 kPrefPreXulSkeletonUI);
2291 Preferences::RegisterCallback(&ReflectSkeletonUIPrefToRegistry,
2292 kPrefBrowserStartupBlankWindow);
2293 Preferences::RegisterCallback(&ReflectSkeletonUIPrefToRegistry, kPrefThemeId);
2294 Preferences::RegisterCallback(
2295 &ReflectSkeletonUIPrefToRegistry,
2296 nsDependentCString(StaticPrefs::GetPrefName_browser_tabs_inTitlebar()));
2299 # if defined(MOZ_LAUNCHER_PROCESS)
2301 static void OnLauncherPrefChanged(const char* aPref, void* aData) {
2302 bool prefVal = Preferences::GetBool(PREF_WIN_LAUNCHER_PROCESS_ENABLED, true);
2304 mozilla::LauncherRegistryInfo launcherRegInfo;
2305 mozilla::DebugOnly<mozilla::LauncherVoidResult> reflectResult =
2306 launcherRegInfo.ReflectPrefToRegistry(prefVal);
2307 MOZ_ASSERT(reflectResult.inspect().isOk());
2310 static void OnLauncherTelemetryPrefChanged(const char* aPref, void* aData) {
2311 bool prefVal = Preferences::GetBool(kPrefHealthReportUploadEnabled, true);
2313 mozilla::LauncherRegistryInfo launcherRegInfo;
2314 mozilla::DebugOnly<mozilla::LauncherVoidResult> reflectResult =
2315 launcherRegInfo.ReflectTelemetryPrefToRegistry(prefVal);
2316 MOZ_ASSERT(reflectResult.inspect().isOk());
2319 static void SetupLauncherProcessPref() {
2320 if (gLauncherProcessState) {
2321 // We've already successfully run
2322 return;
2325 mozilla::LauncherRegistryInfo launcherRegInfo;
2327 mozilla::LauncherResult<mozilla::LauncherRegistryInfo::EnabledState>
2328 enabledState = launcherRegInfo.IsEnabled();
2330 if (enabledState.isOk()) {
2331 gLauncherProcessState = Some(enabledState.unwrap());
2333 CrashReporter::AnnotateCrashReport(
2334 CrashReporter::Annotation::LauncherProcessState,
2335 static_cast<uint32_t>(enabledState.unwrap()));
2337 // Reflect the launcher process registry state into user prefs
2338 Preferences::SetBool(
2339 PREF_WIN_LAUNCHER_PROCESS_ENABLED,
2340 enabledState.unwrap() !=
2341 mozilla::LauncherRegistryInfo::EnabledState::ForceDisabled);
2344 mozilla::DebugOnly<mozilla::LauncherVoidResult> reflectResult =
2345 launcherRegInfo.ReflectTelemetryPrefToRegistry(
2346 Preferences::GetBool(kPrefHealthReportUploadEnabled, true));
2347 MOZ_ASSERT(reflectResult.inspect().isOk());
2349 Preferences::RegisterCallback(&OnLauncherPrefChanged,
2350 PREF_WIN_LAUNCHER_PROCESS_ENABLED);
2351 Preferences::RegisterCallback(&OnLauncherTelemetryPrefChanged,
2352 kPrefHealthReportUploadEnabled);
2355 # endif // defined(MOZ_LAUNCHER_PROCESS)
2357 # if defined(MOZ_DEFAULT_BROWSER_AGENT)
2359 # define DEFAULT_BROWSER_AGENT_KEY_NAME \
2360 "SOFTWARE\\" MOZ_APP_VENDOR "\\" MOZ_APP_NAME "\\Default Browser Agent"
2362 static nsresult PrependRegistryValueName(nsAutoString& aValueName) {
2363 nsresult rv;
2365 nsCOMPtr<nsIFile> binaryPath;
2366 rv = XRE_GetBinaryPath(getter_AddRefs(binaryPath));
2367 NS_ENSURE_SUCCESS(rv, rv);
2369 nsCOMPtr<nsIFile> binaryDir;
2370 rv = binaryPath->GetParent(getter_AddRefs(binaryDir));
2371 NS_ENSURE_SUCCESS(rv, rv);
2373 nsAutoString prefix;
2374 rv = binaryDir->GetPath(prefix);
2375 NS_ENSURE_SUCCESS(rv, rv);
2377 prefix.AppendLiteral("|");
2378 aValueName.Insert(prefix, 0);
2380 return NS_OK;
2383 static void OnDefaultAgentTelemetryPrefChanged(const char* aPref, void* aData) {
2384 nsresult rv;
2385 nsAutoString valueName;
2386 if (strcmp(aPref, kPrefHealthReportUploadEnabled) == 0) {
2387 valueName.AssignLiteral("DisableTelemetry");
2388 } else if (strcmp(aPref, kPrefDefaultAgentEnabled) == 0) {
2389 valueName.AssignLiteral("DisableDefaultBrowserAgent");
2390 } else {
2391 return;
2393 rv = PrependRegistryValueName(valueName);
2394 NS_ENSURE_SUCCESS_VOID(rv);
2396 nsCOMPtr<nsIWindowsRegKey> regKey =
2397 do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv);
2398 NS_ENSURE_SUCCESS_VOID(rv);
2400 nsAutoString keyName;
2401 keyName.AppendLiteral(DEFAULT_BROWSER_AGENT_KEY_NAME);
2402 rv = regKey->Create(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER, keyName,
2403 nsIWindowsRegKey::ACCESS_WRITE);
2405 bool prefVal = Preferences::GetBool(aPref, true);
2407 // We're recording whether the pref is *disabled*, so invert the value.
2408 rv = regKey->WriteIntValue(valueName, prefVal ? 0 : 1);
2409 NS_ENSURE_SUCCESS_VOID(rv);
2412 static void OnSetDefaultBrowserUserChoicePrefChanged(const char* aPref,
2413 void* aData) {
2414 nsresult rv;
2415 if (strcmp(aPref, kPrefSetDefaultBrowserUserChoicePref) != 0) {
2416 return;
2418 nsAutoString valueName;
2419 valueName.AssignLiteral("SetDefaultBrowserUserChoice");
2420 rv = PrependRegistryValueName(valueName);
2421 NS_ENSURE_SUCCESS_VOID(rv);
2423 nsCOMPtr<nsIWindowsRegKey> regKey =
2424 do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv);
2425 NS_ENSURE_SUCCESS_VOID(rv);
2427 nsAutoString keyName;
2428 keyName.AppendLiteral(DEFAULT_BROWSER_AGENT_KEY_NAME);
2429 rv = regKey->Create(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER, keyName,
2430 nsIWindowsRegKey::ACCESS_WRITE);
2432 bool prefVal = Preferences::GetBool(aPref, true);
2434 rv = regKey->WriteIntValue(valueName, prefVal);
2435 NS_ENSURE_SUCCESS_VOID(rv);
2438 static void OnDefaultAgentRemoteSettingsPrefChanged(const char* aPref,
2439 void* aData) {
2440 nsresult rv;
2441 nsAutoString valueName;
2442 if (strcmp(aPref, kPrefServicesSettingsServer) == 0) {
2443 valueName.AssignLiteral("ServicesSettingsServer");
2444 } else if (strcmp(aPref, kPrefSecurityContentSignatureRootHash) == 0) {
2445 valueName.AssignLiteral("SecurityContentSignatureRootHash");
2446 } else {
2447 return;
2449 rv = PrependRegistryValueName(valueName);
2450 NS_ENSURE_SUCCESS_VOID(rv);
2452 nsCOMPtr<nsIWindowsRegKey> regKey =
2453 do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv);
2454 NS_ENSURE_SUCCESS_VOID(rv);
2456 nsAutoString keyName;
2457 keyName.AppendLiteral(DEFAULT_BROWSER_AGENT_KEY_NAME);
2458 rv = regKey->Create(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER, keyName,
2459 nsIWindowsRegKey::ACCESS_WRITE);
2461 NS_ENSURE_SUCCESS_VOID(rv);
2463 nsAutoString prefVal;
2464 rv = Preferences::GetString(aPref, prefVal);
2465 if (NS_FAILED(rv)) {
2466 return;
2469 if (prefVal.IsEmpty()) {
2470 rv = regKey->RemoveValue(valueName);
2471 } else {
2472 rv = regKey->WriteStringValue(valueName, prefVal);
2474 NS_ENSURE_SUCCESS_VOID(rv);
2477 static void SetDefaultAgentLastRunTime() {
2478 nsresult rv;
2479 nsAutoString valueName;
2480 valueName.AppendLiteral("AppLastRunTime");
2481 rv = PrependRegistryValueName(valueName);
2482 NS_ENSURE_SUCCESS_VOID(rv);
2484 nsCOMPtr<nsIWindowsRegKey> regKey =
2485 do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv);
2486 NS_ENSURE_SUCCESS_VOID(rv);
2488 nsAutoString keyName;
2489 keyName.AppendLiteral(DEFAULT_BROWSER_AGENT_KEY_NAME);
2490 rv = regKey->Create(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER, keyName,
2491 nsIWindowsRegKey::ACCESS_WRITE);
2492 NS_ENSURE_SUCCESS_VOID(rv);
2494 FILETIME fileTime;
2495 GetSystemTimeAsFileTime(&fileTime);
2497 ULARGE_INTEGER integerTime;
2498 integerTime.u.LowPart = fileTime.dwLowDateTime;
2499 integerTime.u.HighPart = fileTime.dwHighDateTime;
2501 rv = regKey->WriteInt64Value(valueName, integerTime.QuadPart);
2502 NS_ENSURE_SUCCESS_VOID(rv);
2505 # endif // defined(MOZ_DEFAULT_BROWSER_AGENT)
2507 #endif // XP_WIN
2509 void UnlockProfile() {
2510 if (gProfileLock) {
2511 gProfileLock->Unlock();
2515 nsresult LaunchChild(bool aBlankCommandLine, bool aTryExec) {
2516 // Restart this process by exec'ing it into the current process
2517 // if supported by the platform. Otherwise, use NSPR.
2519 #ifdef MOZ_JPROF
2520 // make sure JPROF doesn't think we're E10s
2521 unsetenv("JPROF_ISCHILD");
2522 #endif
2524 if (aBlankCommandLine) {
2525 gRestartArgc = 1;
2526 gRestartArgv[gRestartArgc] = nullptr;
2529 #if defined(MOZ_HAS_REMOTE)
2530 if (gRestartWithoutRemote) {
2531 SaveToEnv("MOZ_NO_REMOTE=1");
2533 #endif
2535 SaveToEnv("MOZ_LAUNCHED_CHILD=1");
2536 #if defined(MOZ_LAUNCHER_PROCESS)
2537 SaveToEnv("MOZ_LAUNCHER_PROCESS=1");
2538 #endif // defined(MOZ_LAUNCHER_PROCESS)
2540 #if !defined(MOZ_WIDGET_ANDROID) // Android has separate restart code.
2541 # if defined(XP_MACOSX)
2542 CommandLineServiceMac::SetupMacCommandLine(gRestartArgc, gRestartArgv, true);
2543 LaunchChildMac(gRestartArgc, gRestartArgv);
2544 # else
2545 nsCOMPtr<nsIFile> lf;
2546 nsresult rv = XRE_GetBinaryPath(getter_AddRefs(lf));
2547 if (NS_FAILED(rv)) return rv;
2549 # if defined(XP_WIN)
2550 nsAutoString exePath;
2551 rv = lf->GetPath(exePath);
2552 if (NS_FAILED(rv)) return rv;
2554 HANDLE hProcess;
2555 if (!WinLaunchChild(exePath.get(), gRestartArgc, gRestartArgv, nullptr,
2556 &hProcess))
2557 return NS_ERROR_FAILURE;
2558 // Keep the current process around until the restarted process has created
2559 // its message queue, to avoid the launched process's windows being forced
2560 // into the background.
2561 mozilla::WaitForInputIdle(hProcess);
2562 ::CloseHandle(hProcess);
2564 # else
2565 nsAutoCString exePath;
2566 rv = lf->GetNativePath(exePath);
2567 if (NS_FAILED(rv)) return rv;
2569 # if defined(XP_UNIX)
2570 if (aTryExec) {
2571 execv(exePath.get(), gRestartArgv);
2573 // If execv returns we know it's because it failed.
2574 return NS_ERROR_FAILURE;
2576 # endif
2577 if (PR_CreateProcessDetached(exePath.get(), gRestartArgv, nullptr, nullptr) ==
2578 PR_FAILURE) {
2579 return NS_ERROR_FAILURE;
2582 // Note that we don't know if the child process starts okay, if it
2583 // immediately returns non-zero then we may mask that by returning a zero
2584 // exit status.
2586 # endif // WP_WIN
2587 # endif // WP_MACOSX
2588 #endif // MOZ_WIDGET_ANDROID
2590 return NS_ERROR_LAUNCHED_CHILD_PROCESS;
2593 static const char kProfileProperties[] =
2594 "chrome://mozapps/locale/profile/profileSelection.properties";
2596 namespace {
2599 * This class, instead of a raw nsresult, should be the return type of any
2600 * function called by SelectProfile that initializes XPCOM.
2602 class ReturnAbortOnError {
2603 public:
2604 MOZ_IMPLICIT ReturnAbortOnError(nsresult aRv) { mRv = ConvertRv(aRv); }
2606 operator nsresult() { return mRv; }
2608 private:
2609 inline nsresult ConvertRv(nsresult aRv) {
2610 if (NS_SUCCEEDED(aRv) || aRv == NS_ERROR_LAUNCHED_CHILD_PROCESS) {
2611 return aRv;
2613 #ifdef MOZ_BACKGROUNDTASKS
2614 // A background task that fails to lock its profile will return
2615 // NS_ERROR_UNEXPECTED and this will allow the task to exit with a
2616 // non-zero exit code.
2617 if (aRv == NS_ERROR_UNEXPECTED && BackgroundTasks::IsBackgroundTaskMode()) {
2618 return aRv;
2620 #endif
2621 return NS_ERROR_ABORT;
2624 nsresult mRv;
2627 } // namespace
2629 static nsresult ProfileMissingDialog(nsINativeAppSupport* aNative) {
2630 #ifdef MOZ_WIDGET_ANDROID
2631 // We cannot really do anything this early during initialization, so we just
2632 // return as this is likely the effect of misconfiguration on the test side.
2633 // Non-test code paths cannot set the profile folder, which is always the
2634 // default one.
2635 Output(true, "Could not find profile folder.\n");
2636 return NS_ERROR_ABORT;
2637 #else
2638 # ifdef MOZ_BACKGROUNDTASKS
2639 if (BackgroundTasks::IsBackgroundTaskMode()) {
2640 // We should never get to this point in background task mode.
2641 Output(false,
2642 "Could not determine any profile running in backgroundtask mode!\n");
2643 return NS_ERROR_ABORT;
2645 # endif // MOZ_BACKGROUNDTASKS
2647 nsresult rv;
2649 ScopedXPCOMStartup xpcom;
2650 rv = xpcom.Initialize();
2651 NS_ENSURE_SUCCESS(rv, rv);
2653 rv = xpcom.SetWindowCreator(aNative);
2654 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
2656 { // extra scoping is needed so we release these components before xpcom
2657 // shutdown
2658 nsCOMPtr<nsIStringBundleService> sbs =
2659 mozilla::components::StringBundle::Service();
2660 NS_ENSURE_TRUE(sbs, NS_ERROR_FAILURE);
2662 nsCOMPtr<nsIStringBundle> sb;
2663 sbs->CreateBundle(kProfileProperties, getter_AddRefs(sb));
2664 NS_ENSURE_TRUE_LOG(sbs, NS_ERROR_FAILURE);
2666 NS_ConvertUTF8toUTF16 appName(gAppData->name);
2667 AutoTArray<nsString, 2> params = {appName, appName};
2669 // profileMissing
2670 nsAutoString missingMessage;
2671 rv = sb->FormatStringFromName("profileMissing", params, missingMessage);
2672 NS_ENSURE_SUCCESS(rv, NS_ERROR_ABORT);
2674 nsAutoString missingTitle;
2675 params.SetLength(1);
2676 rv = sb->FormatStringFromName("profileMissingTitle", params, missingTitle);
2677 NS_ENSURE_SUCCESS(rv, NS_ERROR_ABORT);
2679 nsCOMPtr<nsIPromptService> ps(do_GetService(NS_PROMPTSERVICE_CONTRACTID));
2680 NS_ENSURE_TRUE(ps, NS_ERROR_FAILURE);
2682 ps->Alert(nullptr, missingTitle.get(), missingMessage.get());
2684 return NS_ERROR_ABORT;
2686 #endif // MOZ_WIDGET_ANDROID
2689 static ReturnAbortOnError ProfileLockedDialog(nsIFile* aProfileDir,
2690 nsIFile* aProfileLocalDir,
2691 nsIProfileUnlocker* aUnlocker,
2692 nsINativeAppSupport* aNative,
2693 nsIProfileLock** aResult) {
2694 nsresult rv;
2696 bool exists;
2697 aProfileDir->Exists(&exists);
2698 if (!exists) {
2699 return ProfileMissingDialog(aNative);
2702 ScopedXPCOMStartup xpcom;
2703 rv = xpcom.Initialize();
2704 NS_ENSURE_SUCCESS(rv, rv);
2706 #if defined(MOZ_TELEMETRY_REPORTING)
2707 // We cannot check if telemetry has been disabled by the user, yet.
2708 // So, rely on the build time settings, instead.
2709 mozilla::Telemetry::WriteFailedProfileLock(aProfileDir);
2710 #endif
2712 rv = xpcom.SetWindowCreator(aNative);
2713 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
2715 { // extra scoping is needed so we release these components before xpcom
2716 // shutdown
2717 nsCOMPtr<nsIStringBundleService> sbs =
2718 mozilla::components::StringBundle::Service();
2719 NS_ENSURE_TRUE(sbs, NS_ERROR_FAILURE);
2721 nsCOMPtr<nsIStringBundle> sb;
2722 sbs->CreateBundle(kProfileProperties, getter_AddRefs(sb));
2723 NS_ENSURE_TRUE_LOG(sbs, NS_ERROR_FAILURE);
2725 NS_ConvertUTF8toUTF16 appName(gAppData->name);
2726 AutoTArray<nsString, 3> params = {appName, appName, appName};
2728 nsAutoString killMessage;
2729 #ifndef XP_MACOSX
2730 rv = sb->FormatStringFromName(
2731 aUnlocker ? "restartMessageUnlocker" : "restartMessageNoUnlocker2",
2732 params, killMessage);
2733 #else
2734 rv = sb->FormatStringFromName(
2735 aUnlocker ? "restartMessageUnlockerMac" : "restartMessageNoUnlockerMac",
2736 params, killMessage);
2737 #endif
2738 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
2740 params.SetLength(1);
2741 nsAutoString killTitle;
2742 rv = sb->FormatStringFromName("restartTitle", params, killTitle);
2743 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
2745 #ifdef MOZ_BACKGROUNDTASKS
2746 if (BackgroundTasks::IsBackgroundTaskMode()) {
2747 // This error is handled specially to exit with a non-zero exit code.
2748 printf_stderr("%s\n", NS_LossyConvertUTF16toASCII(killMessage).get());
2749 return NS_ERROR_UNEXPECTED;
2751 #endif
2753 if (gfxPlatform::IsHeadless()) {
2754 // TODO: make a way to turn off all dialogs when headless.
2755 Output(true, "%s\n", NS_LossyConvertUTF16toASCII(killMessage).get());
2756 return NS_ERROR_FAILURE;
2759 nsCOMPtr<nsIPromptService> ps(do_GetService(NS_PROMPTSERVICE_CONTRACTID));
2760 NS_ENSURE_TRUE(ps, NS_ERROR_FAILURE);
2762 if (aUnlocker) {
2763 int32_t button;
2764 #ifdef MOZ_WIDGET_ANDROID
2765 // On Android we always kill the process if the lock is still being held
2766 button = 0;
2767 #else
2768 const uint32_t flags = (nsIPromptService::BUTTON_TITLE_IS_STRING *
2769 nsIPromptService::BUTTON_POS_0) +
2770 (nsIPromptService::BUTTON_TITLE_CANCEL *
2771 nsIPromptService::BUTTON_POS_1);
2773 bool checkState = false;
2774 rv = ps->ConfirmEx(nullptr, killTitle.get(), killMessage.get(), flags,
2775 killTitle.get(), nullptr, nullptr, nullptr,
2776 &checkState, &button);
2777 NS_ENSURE_SUCCESS_LOG(rv, rv);
2778 #endif
2780 if (button == 0) {
2781 rv = aUnlocker->Unlock(nsIProfileUnlocker::FORCE_QUIT);
2782 if (NS_FAILED(rv)) {
2783 return rv;
2786 SaveFileToEnv("XRE_PROFILE_PATH", aProfileDir);
2787 SaveFileToEnv("XRE_PROFILE_LOCAL_PATH", aProfileLocalDir);
2789 #if defined(MOZ_HAS_REMOTE)
2790 if (gRemoteService) {
2791 gRemoteService->UnlockStartup();
2792 gRemoteService = nullptr;
2794 #endif
2795 return LaunchChild(false, true);
2797 } else {
2798 rv = ps->Alert(nullptr, killTitle.get(), killMessage.get());
2799 NS_ENSURE_SUCCESS_LOG(rv, rv);
2802 return NS_ERROR_ABORT;
2806 static const char kProfileManagerURL[] =
2807 "chrome://mozapps/content/profile/profileSelection.xhtml";
2809 static ReturnAbortOnError ShowProfileManager(
2810 nsIToolkitProfileService* aProfileSvc, nsINativeAppSupport* aNative) {
2811 nsresult rv;
2813 nsCOMPtr<nsIFile> profD, profLD;
2814 bool offline = false;
2815 int32_t dialogReturn;
2818 ScopedXPCOMStartup xpcom;
2819 rv = xpcom.Initialize();
2820 NS_ENSURE_SUCCESS(rv, rv);
2822 rv = xpcom.SetWindowCreator(aNative);
2823 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
2825 #ifdef XP_MACOSX
2826 CommandLineServiceMac::SetupMacCommandLine(gRestartArgc, gRestartArgv,
2827 true);
2828 #endif
2830 { // extra scoping is needed so we release these components before xpcom
2831 // shutdown
2832 nsCOMPtr<nsIWindowWatcher> windowWatcher(
2833 do_GetService(NS_WINDOWWATCHER_CONTRACTID));
2834 nsCOMPtr<nsIDialogParamBlock> ioParamBlock(
2835 do_CreateInstance(NS_DIALOGPARAMBLOCK_CONTRACTID));
2836 nsCOMPtr<nsIMutableArray> dlgArray(
2837 do_CreateInstance(NS_ARRAY_CONTRACTID));
2838 NS_ENSURE_TRUE(windowWatcher && ioParamBlock && dlgArray,
2839 NS_ERROR_FAILURE);
2841 ioParamBlock->SetObjects(dlgArray);
2843 nsCOMPtr<nsIAppStartup> appStartup(components::AppStartup::Service());
2844 NS_ENSURE_TRUE(appStartup, NS_ERROR_FAILURE);
2846 nsAutoCString features("centerscreen,chrome,modal,titlebar");
2847 // If we're launching a private browsing window make sure to set that
2848 // feature for the Profile Manager window as well, so it groups correctly
2849 // on the Windows taskbar.
2850 if (CheckArgExists("private-window") == ARG_FOUND) {
2851 features.AppendLiteral(",private");
2853 nsCOMPtr<mozIDOMWindowProxy> newWindow;
2854 rv = windowWatcher->OpenWindow(
2855 nullptr, nsDependentCString(kProfileManagerURL), "_blank"_ns,
2856 features, ioParamBlock, getter_AddRefs(newWindow));
2858 NS_ENSURE_SUCCESS_LOG(rv, rv);
2860 rv = ioParamBlock->GetInt(0, &dialogReturn);
2861 if (NS_FAILED(rv) || dialogReturn == nsIToolkitProfileService::exit) {
2862 return NS_ERROR_ABORT;
2865 int32_t startOffline;
2866 rv = ioParamBlock->GetInt(1, &startOffline);
2867 offline = NS_SUCCEEDED(rv) && startOffline == 1;
2869 rv = dlgArray->QueryElementAt(0, NS_GET_IID(nsIFile),
2870 getter_AddRefs(profD));
2871 NS_ENSURE_SUCCESS_LOG(rv, rv);
2873 rv = dlgArray->QueryElementAt(1, NS_GET_IID(nsIFile),
2874 getter_AddRefs(profLD));
2875 NS_ENSURE_SUCCESS_LOG(rv, rv);
2879 if (offline) {
2880 SaveToEnv("XRE_START_OFFLINE=1");
2883 // User requested that we restart back into the profile manager.
2884 if (dialogReturn == nsIToolkitProfileService::restart) {
2885 SaveToEnv("XRE_RESTART_TO_PROFILE_MANAGER=1");
2886 SaveToEnv("XRE_RESTARTED_BY_PROFILE_MANAGER=1");
2887 } else {
2888 MOZ_ASSERT(dialogReturn == nsIToolkitProfileService::launchWithProfile);
2889 SaveFileToEnv("XRE_PROFILE_PATH", profD);
2890 SaveFileToEnv("XRE_PROFILE_LOCAL_PATH", profLD);
2891 SaveToEnv("XRE_RESTARTED_BY_PROFILE_MANAGER=1");
2894 if (gRestartedByOS) {
2895 // Re-add this argument when actually starting the application.
2896 char** newArgv =
2897 (char**)realloc(gRestartArgv, sizeof(char*) * (gRestartArgc + 2));
2898 NS_ENSURE_TRUE(newArgv, NS_ERROR_OUT_OF_MEMORY);
2899 gRestartArgv = newArgv;
2900 gRestartArgv[gRestartArgc++] = const_cast<char*>("-os-restarted");
2901 gRestartArgv[gRestartArgc] = nullptr;
2903 #if defined(MOZ_HAS_REMOTE)
2904 if (gRemoteService) {
2905 gRemoteService->UnlockStartup();
2906 gRemoteService = nullptr;
2908 #endif
2909 return LaunchChild(false, true);
2912 static bool gDoMigration = false;
2913 static bool gDoProfileReset = false;
2914 static nsCOMPtr<nsIToolkitProfile> gResetOldProfile;
2916 static nsresult LockProfile(nsINativeAppSupport* aNative, nsIFile* aRootDir,
2917 nsIFile* aLocalDir, nsIToolkitProfile* aProfile,
2918 nsIProfileLock** aResult) {
2919 // If you close Firefox and very quickly reopen it, the old Firefox may
2920 // still be closing down. Rather than immediately showing the
2921 // "Firefox is running but is not responding" message, we spend a few
2922 // seconds retrying first.
2924 static const int kLockRetrySeconds = 5;
2925 static const int kLockRetrySleepMS = 100;
2927 nsresult rv;
2928 nsCOMPtr<nsIProfileUnlocker> unlocker;
2929 const TimeStamp start = TimeStamp::Now();
2930 do {
2931 if (aProfile) {
2932 rv = aProfile->Lock(getter_AddRefs(unlocker), aResult);
2933 } else {
2934 rv = NS_LockProfilePath(aRootDir, aLocalDir, getter_AddRefs(unlocker),
2935 aResult);
2937 if (NS_SUCCEEDED(rv)) {
2938 StartupTimeline::Record(StartupTimeline::AFTER_PROFILE_LOCKED);
2939 return NS_OK;
2941 PR_Sleep(kLockRetrySleepMS);
2942 } while (TimeStamp::Now() - start <
2943 TimeDuration::FromSeconds(kLockRetrySeconds));
2945 return ProfileLockedDialog(aRootDir, aLocalDir, unlocker, aNative, aResult);
2948 // Pick a profile. We need to end up with a profile root dir, local dir and
2949 // potentially an nsIToolkitProfile instance.
2951 // 1) check for --profile <path>
2952 // 2) check for -P <name>
2953 // 3) check for --ProfileManager
2954 // 4) use the default profile, if there is one
2955 // 5) if there are *no* profiles, set up profile-migration
2956 // 6) display the profile-manager UI
2957 static nsresult SelectProfile(nsToolkitProfileService* aProfileSvc,
2958 nsINativeAppSupport* aNative, nsIFile** aRootDir,
2959 nsIFile** aLocalDir, nsIToolkitProfile** aProfile,
2960 bool* aWasDefaultSelection) {
2961 StartupTimeline::Record(StartupTimeline::SELECT_PROFILE);
2963 nsresult rv;
2965 if (EnvHasValue("MOZ_RESET_PROFILE_RESTART")) {
2966 gDoProfileReset = true;
2967 gDoMigration = true;
2970 // reset-profile and migration args need to be checked before any profiles are
2971 // chosen below.
2972 ArgResult ar = CheckArg("reset-profile");
2973 if (ar == ARG_FOUND) {
2974 gDoProfileReset = true;
2977 ar = CheckArg("migration");
2978 if (ar == ARG_FOUND) {
2979 gDoMigration = true;
2982 #if defined(XP_WIN)
2983 // This arg is only used to indicate to telemetry that a profile refresh
2984 // (reset+migration) was requested from the uninstaller, pass this along
2985 // via an environment variable for simplicity.
2986 ar = CheckArg("uninstaller-profile-refresh");
2987 if (ar == ARG_FOUND) {
2988 SaveToEnv("MOZ_UNINSTALLER_PROFILE_REFRESH=1");
2990 #endif
2992 if (EnvHasValue("XRE_RESTART_TO_PROFILE_MANAGER")) {
2993 return ShowProfileManager(aProfileSvc, aNative);
2996 // Ask the profile manager to select the profile directories to use.
2997 bool didCreate = false;
2998 rv = aProfileSvc->SelectStartupProfile(&gArgc, gArgv, gDoProfileReset,
2999 aRootDir, aLocalDir, aProfile,
3000 &didCreate, aWasDefaultSelection);
3002 if (rv == NS_ERROR_SHOW_PROFILE_MANAGER) {
3003 return ShowProfileManager(aProfileSvc, aNative);
3006 NS_ENSURE_SUCCESS(rv, rv);
3008 if (didCreate) {
3009 // For a fresh install, we would like to let users decide
3010 // to do profile migration on their own later after using.
3011 gDoProfileReset = false;
3012 gDoMigration = false;
3015 if (gDoProfileReset && !*aProfile) {
3016 NS_WARNING("Profile reset is only supported for named profiles.");
3017 return NS_ERROR_ABORT;
3020 // No profile could be found. This generally shouldn't happen, a new profile
3021 // should be created in all cases except for profile reset which is covered
3022 // above, but just in case...
3023 if (!*aRootDir) {
3024 NS_WARNING("Failed to select or create profile.");
3025 return NS_ERROR_ABORT;
3028 return NS_OK;
3031 #ifdef MOZ_BLOCK_PROFILE_DOWNGRADE
3032 struct FileWriteFunc final : public JSONWriteFunc {
3033 FILE* mFile;
3034 explicit FileWriteFunc(FILE* aFile) : mFile(aFile) {}
3036 void Write(const Span<const char>& aStr) final {
3037 fprintf(mFile, "%.*s", int(aStr.size()), aStr.data());
3041 static void SubmitDowngradeTelemetry(const nsCString& aLastVersion,
3042 bool aHasSync, int32_t aButton) {
3043 nsCOMPtr<nsIPrefService> prefSvc =
3044 do_GetService("@mozilla.org/preferences-service;1");
3045 NS_ENSURE_TRUE_VOID(prefSvc);
3047 nsCOMPtr<nsIPrefBranch> prefBranch = do_QueryInterface(prefSvc);
3048 NS_ENSURE_TRUE_VOID(prefBranch);
3050 bool enabled;
3051 nsresult rv =
3052 prefBranch->GetBoolPref(kPrefHealthReportUploadEnabled, &enabled);
3053 NS_ENSURE_SUCCESS_VOID(rv);
3054 if (!enabled) {
3055 return;
3058 nsCString server;
3059 rv = prefBranch->GetCharPref("toolkit.telemetry.server", server);
3060 NS_ENSURE_SUCCESS_VOID(rv);
3062 nsCString clientId;
3063 rv = prefBranch->GetCharPref("toolkit.telemetry.cachedClientID", clientId);
3064 NS_ENSURE_SUCCESS_VOID(rv);
3066 rv = prefSvc->GetDefaultBranch(nullptr, getter_AddRefs(prefBranch));
3067 NS_ENSURE_SUCCESS_VOID(rv);
3069 nsCString channel("default");
3070 rv = prefBranch->GetCharPref("app.update.channel", channel);
3071 NS_ENSURE_SUCCESS_VOID(rv);
3073 nsID uuid;
3074 rv = nsID::GenerateUUIDInPlace(uuid);
3075 NS_ENSURE_SUCCESS_VOID(rv);
3077 nsCString arch("null");
3078 nsCOMPtr<nsIPropertyBag2> sysInfo =
3079 do_GetService("@mozilla.org/system-info;1");
3080 NS_ENSURE_TRUE_VOID(sysInfo);
3081 sysInfo->GetPropertyAsACString(u"arch"_ns, arch);
3083 time_t now;
3084 time(&now);
3085 char date[sizeof "YYYY-MM-DDThh:mm:ss.000Z"];
3086 strftime(date, sizeof date, "%FT%T.000Z", gmtime(&now));
3088 NSID_TrimBracketsASCII pingId(uuid);
3089 constexpr auto pingType = "downgrade"_ns;
3091 int32_t pos = aLastVersion.Find("_");
3092 if (pos == kNotFound) {
3093 return;
3096 const nsDependentCSubstring lastVersion = Substring(aLastVersion, 0, pos);
3097 const nsDependentCSubstring lastBuildId =
3098 Substring(aLastVersion, pos + 1, 14);
3100 nsPrintfCString url("%s/submit/telemetry/%s/%s/%s/%s/%s/%s?v=%d",
3101 server.get(), PromiseFlatCString(pingId).get(),
3102 pingType.get(), (const char*)gAppData->name,
3103 (const char*)gAppData->version, channel.get(),
3104 (const char*)gAppData->buildID,
3105 TELEMETRY_PING_FORMAT_VERSION);
3107 nsCOMPtr<nsIFile> pingFile;
3108 rv = NS_GetSpecialDirectory(XRE_USER_APP_DATA_DIR, getter_AddRefs(pingFile));
3109 NS_ENSURE_SUCCESS_VOID(rv);
3110 rv = pingFile->Append(u"Pending Pings"_ns);
3111 NS_ENSURE_SUCCESS_VOID(rv);
3112 rv = pingFile->Create(nsIFile::DIRECTORY_TYPE, 0755);
3113 if (NS_FAILED(rv) && rv != NS_ERROR_FILE_ALREADY_EXISTS) {
3114 return;
3116 rv = pingFile->Append(NS_ConvertUTF8toUTF16(pingId));
3117 NS_ENSURE_SUCCESS_VOID(rv);
3119 nsCOMPtr<nsIFile> pingSender;
3120 rv = NS_GetSpecialDirectory(NS_GRE_BIN_DIR, getter_AddRefs(pingSender));
3121 NS_ENSURE_SUCCESS_VOID(rv);
3122 # ifdef XP_WIN
3123 pingSender->Append(u"pingsender.exe"_ns);
3124 # else
3125 pingSender->Append(u"pingsender"_ns);
3126 # endif
3128 bool exists;
3129 rv = pingSender->Exists(&exists);
3130 NS_ENSURE_SUCCESS_VOID(rv);
3131 if (!exists) {
3132 return;
3135 FILE* file;
3136 rv = pingFile->OpenANSIFileDesc("w", &file);
3137 NS_ENSURE_SUCCESS_VOID(rv);
3139 JSONWriter w(MakeUnique<FileWriteFunc>(file));
3140 w.Start();
3142 w.StringProperty("type",
3143 Span<const char>(pingType.Data(), pingType.Length()));
3144 w.StringProperty("id", PromiseFlatCString(pingId));
3145 w.StringProperty("creationDate", MakeStringSpan(date));
3146 w.IntProperty("version", TELEMETRY_PING_FORMAT_VERSION);
3147 w.StringProperty("clientId", clientId);
3148 w.StartObjectProperty("application");
3150 w.StringProperty("architecture", arch);
3151 w.StringProperty(
3152 "buildId",
3153 MakeStringSpan(static_cast<const char*>(gAppData->buildID)));
3154 w.StringProperty(
3155 "name", MakeStringSpan(static_cast<const char*>(gAppData->name)));
3156 w.StringProperty(
3157 "version",
3158 MakeStringSpan(static_cast<const char*>(gAppData->version)));
3159 w.StringProperty("displayVersion",
3160 MOZ_STRINGIFY(MOZ_APP_VERSION_DISPLAY));
3161 w.StringProperty(
3162 "vendor", MakeStringSpan(static_cast<const char*>(gAppData->vendor)));
3163 w.StringProperty("platformVersion", gToolkitVersion);
3164 # ifdef TARGET_XPCOM_ABI
3165 w.StringProperty("xpcomAbi", TARGET_XPCOM_ABI);
3166 # else
3167 w.StringProperty("xpcomAbi", "unknown");
3168 # endif
3169 w.StringProperty("channel", channel);
3171 w.EndObject();
3172 w.StartObjectProperty("payload");
3174 w.StringProperty("lastVersion", PromiseFlatCString(lastVersion));
3175 w.StringProperty("lastBuildId", PromiseFlatCString(lastBuildId));
3176 w.BoolProperty("hasSync", aHasSync);
3177 w.IntProperty("button", aButton);
3179 w.EndObject();
3181 w.End();
3183 fclose(file);
3185 PathString filePath = pingFile->NativePath();
3186 const filesystem::Path::value_type* args[2];
3187 # ifdef XP_WIN
3188 nsString urlw = NS_ConvertUTF8toUTF16(url);
3189 args[0] = urlw.get();
3190 # else
3191 args[0] = url.get();
3192 # endif
3193 args[1] = filePath.get();
3195 nsCOMPtr<nsIProcess> process =
3196 do_CreateInstance("@mozilla.org/process/util;1");
3197 NS_ENSURE_TRUE_VOID(process);
3198 process->Init(pingSender);
3199 process->SetStartHidden(true);
3200 process->SetNoShell(true);
3202 # ifdef XP_WIN
3203 process->Runw(false, args, 2);
3204 # else
3205 process->Run(false, args, 2);
3206 # endif
3209 static const char kProfileDowngradeURL[] =
3210 "chrome://mozapps/content/profile/profileDowngrade.xhtml";
3212 static ReturnAbortOnError CheckDowngrade(nsIFile* aProfileDir,
3213 nsINativeAppSupport* aNative,
3214 nsIToolkitProfileService* aProfileSvc,
3215 const nsCString& aLastVersion) {
3216 int32_t result = 0;
3217 nsresult rv;
3220 if (gfxPlatform::IsHeadless()) {
3221 // TODO: make a way to turn off all dialogs when headless.
3222 Output(true,
3223 "This profile was last used with a newer version of this "
3224 "application. Please create a new profile.\n");
3225 return NS_ERROR_ABORT;
3228 ScopedXPCOMStartup xpcom;
3229 rv = xpcom.Initialize();
3230 NS_ENSURE_SUCCESS(rv, rv);
3232 rv = xpcom.SetWindowCreator(aNative);
3233 NS_ENSURE_SUCCESS(rv, rv);
3235 { // extra scoping is needed so we release these components before xpcom
3236 // shutdown
3237 bool hasSync = false;
3238 nsCOMPtr<nsIPrefService> prefSvc =
3239 do_GetService("@mozilla.org/preferences-service;1");
3240 NS_ENSURE_TRUE(prefSvc, rv);
3242 nsCOMPtr<nsIFile> prefsFile;
3243 rv = aProfileDir->Clone(getter_AddRefs(prefsFile));
3244 NS_ENSURE_SUCCESS(rv, rv);
3246 rv = prefsFile->Append(u"prefs.js"_ns);
3247 NS_ENSURE_SUCCESS(rv, rv);
3249 rv = prefSvc->ReadUserPrefsFromFile(prefsFile);
3250 if (NS_SUCCEEDED(rv)) {
3251 nsCOMPtr<nsIPrefBranch> prefBranch = do_QueryInterface(prefSvc);
3253 rv = prefBranch->PrefHasUserValue("services.sync.username", &hasSync);
3254 NS_ENSURE_SUCCESS(rv, rv);
3257 nsCOMPtr<nsIWindowWatcher> windowWatcher =
3258 do_GetService(NS_WINDOWWATCHER_CONTRACTID);
3259 NS_ENSURE_TRUE(windowWatcher, NS_ERROR_ABORT);
3261 nsCOMPtr<nsIAppStartup> appStartup(components::AppStartup::Service());
3262 NS_ENSURE_TRUE(appStartup, NS_ERROR_FAILURE);
3264 nsCOMPtr<nsIDialogParamBlock> paramBlock =
3265 do_CreateInstance(NS_DIALOGPARAMBLOCK_CONTRACTID);
3266 NS_ENSURE_TRUE(paramBlock, NS_ERROR_ABORT);
3268 uint8_t flags = 0;
3269 if (hasSync) {
3270 flags |= nsIToolkitProfileService::hasSync;
3273 paramBlock->SetInt(0, flags);
3275 nsAutoCString features("centerscreen,chrome,modal,titlebar");
3276 // If we're launching a private browsing window make sure to set that
3277 // feature for the Profile Manager window as well, so it groups correctly
3278 // on the Windows taskbar.
3279 if (CheckArgExists("private-window") == ARG_FOUND) {
3280 features.AppendLiteral(",private");
3282 nsCOMPtr<mozIDOMWindowProxy> newWindow;
3283 rv = windowWatcher->OpenWindow(
3284 nullptr, nsDependentCString(kProfileDowngradeURL), "_blank"_ns,
3285 features, paramBlock, getter_AddRefs(newWindow));
3286 NS_ENSURE_SUCCESS(rv, rv);
3288 paramBlock->GetInt(1, &result);
3290 SubmitDowngradeTelemetry(aLastVersion, hasSync, result);
3294 if (result == nsIToolkitProfileService::createNewProfile) {
3295 // Create a new profile and start it.
3296 nsCString profileName;
3297 profileName.AssignLiteral("default");
3298 # ifdef MOZ_DEDICATED_PROFILES
3299 profileName.Append("-" MOZ_STRINGIFY(MOZ_UPDATE_CHANNEL));
3300 # endif
3301 nsCOMPtr<nsIToolkitProfile> newProfile;
3302 rv = aProfileSvc->CreateUniqueProfile(nullptr, profileName,
3303 getter_AddRefs(newProfile));
3304 NS_ENSURE_SUCCESS(rv, rv);
3305 rv = aProfileSvc->SetDefaultProfile(newProfile);
3306 NS_ENSURE_SUCCESS(rv, rv);
3307 rv = aProfileSvc->Flush();
3308 NS_ENSURE_SUCCESS(rv, rv);
3310 nsCOMPtr<nsIFile> profD, profLD;
3311 rv = newProfile->GetRootDir(getter_AddRefs(profD));
3312 NS_ENSURE_SUCCESS(rv, rv);
3313 rv = newProfile->GetLocalDir(getter_AddRefs(profLD));
3314 NS_ENSURE_SUCCESS(rv, rv);
3316 SaveFileToEnv("XRE_PROFILE_PATH", profD);
3317 SaveFileToEnv("XRE_PROFILE_LOCAL_PATH", profLD);
3319 return LaunchChild(false, true);
3322 // Cancel
3323 return NS_ERROR_ABORT;
3325 #endif
3328 * Extracts the various parts of a compatibility version string.
3330 * Compatibility versions are of the form
3331 * "<appversion>_<appbuildid>/<platformbuildid>". The toolkit version comparator
3332 * can only handle 32-bit numbers and in the normal case build IDs are larger
3333 * than this. So if the build ID is numeric we split it into two version parts.
3335 static void ExtractCompatVersionInfo(const nsACString& aCompatVersion,
3336 nsACString& aAppVersion,
3337 nsACString& aAppBuildID) {
3338 int32_t underscorePos = aCompatVersion.FindChar('_');
3339 int32_t slashPos = aCompatVersion.FindChar('/');
3341 if (underscorePos == kNotFound || slashPos == kNotFound ||
3342 slashPos < underscorePos) {
3343 NS_WARNING(
3344 "compatibility.ini Version string does not match the expected format.");
3346 // Fall back to just using the entire string as the version.
3347 aAppVersion = aCompatVersion;
3348 aAppBuildID.Truncate(0);
3349 return;
3352 aAppVersion = Substring(aCompatVersion, 0, underscorePos);
3353 aAppBuildID = Substring(aCompatVersion, underscorePos + 1,
3354 slashPos - (underscorePos + 1));
3358 * Compares the provided compatibility versions. Returns 0 if they match,
3359 * < 0 if the new version is considered an upgrade from the old version and
3360 * > 0 if the new version is considered a downgrade from the old version.
3362 int32_t CompareCompatVersions(const nsACString& aOldCompatVersion,
3363 const nsACString& aNewCompatVersion) {
3364 // Hardcode the case where the last run was in safe mode (Bug 1556612). We
3365 // cannot tell if this is a downgrade or not so just assume it isn't and let
3366 // the user proceed.
3367 if (aOldCompatVersion.EqualsLiteral("Safe Mode")) {
3368 return -1;
3371 // Extract the major version part from the version string and only use that
3372 // for version comparison.
3373 int32_t index = aOldCompatVersion.FindChar('.');
3374 const nsACString& oldMajorVersion = Substring(
3375 aOldCompatVersion, 0, index < 0 ? aOldCompatVersion.Length() : index);
3376 index = aNewCompatVersion.FindChar('.');
3377 const nsACString& newMajorVersion = Substring(
3378 aNewCompatVersion, 0, index < 0 ? aNewCompatVersion.Length() : index);
3380 return CompareVersions(PromiseFlatCString(oldMajorVersion).get(),
3381 PromiseFlatCString(newMajorVersion).get());
3385 * Checks the compatibility.ini file to see if we have updated our application
3386 * or otherwise invalidated our caches. If the application has been updated,
3387 * we return false; otherwise, we return true.
3389 * We also write the status of the caches (valid/invalid) into the return param
3390 * aCachesOK. The aCachesOK is always invalid if the application has been
3391 * updated.
3393 * Finally, aIsDowngrade is set to true if the current application is older
3394 * than that previously used by the profile.
3396 static bool CheckCompatibility(nsIFile* aProfileDir, const nsCString& aVersion,
3397 const nsCString& aOSABI, nsIFile* aXULRunnerDir,
3398 nsIFile* aAppDir, nsIFile* aFlagFile,
3399 bool* aCachesOK, bool* aIsDowngrade,
3400 nsCString& aLastVersion) {
3401 *aCachesOK = false;
3402 *aIsDowngrade = false;
3403 gLastAppVersion.SetIsVoid(true);
3404 gLastAppBuildID.SetIsVoid(true);
3406 nsCOMPtr<nsIFile> file;
3407 aProfileDir->Clone(getter_AddRefs(file));
3408 if (!file) return false;
3409 file->AppendNative(FILE_COMPATIBILITY_INFO);
3411 nsINIParser parser;
3412 nsresult rv = parser.Init(file);
3413 if (NS_FAILED(rv)) return false;
3415 rv = parser.GetString("Compatibility", "LastVersion", aLastVersion);
3416 if (NS_FAILED(rv)) {
3417 return false;
3420 if (!aLastVersion.Equals(aVersion)) {
3421 // The version is not the same. Whether it's a downgrade depends on an
3422 // actual comparison:
3423 *aIsDowngrade = 0 < CompareCompatVersions(aLastVersion, aVersion);
3424 ExtractCompatVersionInfo(aLastVersion, gLastAppVersion, gLastAppBuildID);
3425 return false;
3428 // If we get here, the version matched, but there may still be other
3429 // differences between us and the build that the profile last ran under.
3431 gLastAppVersion.Assign(gAppData->version);
3432 gLastAppBuildID.Assign(gAppData->buildID);
3434 nsAutoCString buf;
3435 rv = parser.GetString("Compatibility", "LastOSABI", buf);
3436 if (NS_FAILED(rv) || !aOSABI.Equals(buf)) return false;
3438 rv = parser.GetString("Compatibility", "LastPlatformDir", buf);
3439 if (NS_FAILED(rv)) return false;
3441 nsCOMPtr<nsIFile> lf;
3442 rv = NS_NewNativeLocalFile(""_ns, false, getter_AddRefs(lf));
3443 if (NS_FAILED(rv)) return false;
3445 rv = lf->SetPersistentDescriptor(buf);
3446 if (NS_FAILED(rv)) return false;
3448 bool eq;
3449 rv = lf->Equals(aXULRunnerDir, &eq);
3450 if (NS_FAILED(rv) || !eq) return false;
3452 if (aAppDir) {
3453 rv = parser.GetString("Compatibility", "LastAppDir", buf);
3454 if (NS_FAILED(rv)) return false;
3456 rv = NS_NewNativeLocalFile(""_ns, false, getter_AddRefs(lf));
3457 if (NS_FAILED(rv)) return false;
3459 rv = lf->SetPersistentDescriptor(buf);
3460 if (NS_FAILED(rv)) return false;
3462 rv = lf->Equals(aAppDir, &eq);
3463 if (NS_FAILED(rv) || !eq) return false;
3466 // If we see this flag, caches are invalid.
3467 rv = parser.GetString("Compatibility", "InvalidateCaches", buf);
3468 *aCachesOK = (NS_FAILED(rv) || !buf.EqualsLiteral("1"));
3470 bool purgeCaches = false;
3471 if (aFlagFile && NS_SUCCEEDED(aFlagFile->Exists(&purgeCaches)) &&
3472 purgeCaches) {
3473 *aCachesOK = false;
3476 return true;
3479 void BuildCompatVersion(const char* aAppVersion, const char* aAppBuildID,
3480 const char* aToolkitBuildID, nsACString& aBuf) {
3481 aBuf.Assign(aAppVersion);
3482 aBuf.Append('_');
3483 aBuf.Append(aAppBuildID);
3484 aBuf.Append('/');
3485 aBuf.Append(aToolkitBuildID);
3488 static void BuildVersion(nsCString& aBuf) {
3489 BuildCompatVersion(gAppData->version, gAppData->buildID, gToolkitBuildID,
3490 aBuf);
3493 static void WriteVersion(nsIFile* aProfileDir, const nsCString& aVersion,
3494 const nsCString& aOSABI, nsIFile* aXULRunnerDir,
3495 nsIFile* aAppDir, bool invalidateCache) {
3496 nsCOMPtr<nsIFile> file;
3497 aProfileDir->Clone(getter_AddRefs(file));
3498 if (!file) return;
3499 file->AppendNative(FILE_COMPATIBILITY_INFO);
3501 nsAutoCString platformDir;
3502 Unused << aXULRunnerDir->GetPersistentDescriptor(platformDir);
3504 nsAutoCString appDir;
3505 if (aAppDir) Unused << aAppDir->GetPersistentDescriptor(appDir);
3507 PRFileDesc* fd;
3508 nsresult rv = file->OpenNSPRFileDesc(PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE,
3509 0600, &fd);
3510 if (NS_FAILED(rv)) {
3511 NS_ERROR("could not create output stream");
3512 return;
3515 static const char kHeader[] = "[Compatibility]" NS_LINEBREAK "LastVersion=";
3517 PR_Write(fd, kHeader, sizeof(kHeader) - 1);
3518 PR_Write(fd, aVersion.get(), aVersion.Length());
3520 static const char kOSABIHeader[] = NS_LINEBREAK "LastOSABI=";
3521 PR_Write(fd, kOSABIHeader, sizeof(kOSABIHeader) - 1);
3522 PR_Write(fd, aOSABI.get(), aOSABI.Length());
3524 static const char kPlatformDirHeader[] = NS_LINEBREAK "LastPlatformDir=";
3526 PR_Write(fd, kPlatformDirHeader, sizeof(kPlatformDirHeader) - 1);
3527 PR_Write(fd, platformDir.get(), platformDir.Length());
3529 static const char kAppDirHeader[] = NS_LINEBREAK "LastAppDir=";
3530 if (aAppDir) {
3531 PR_Write(fd, kAppDirHeader, sizeof(kAppDirHeader) - 1);
3532 PR_Write(fd, appDir.get(), appDir.Length());
3535 static const char kInvalidationHeader[] = NS_LINEBREAK "InvalidateCaches=1";
3536 if (invalidateCache)
3537 PR_Write(fd, kInvalidationHeader, sizeof(kInvalidationHeader) - 1);
3539 static const char kNL[] = NS_LINEBREAK;
3540 PR_Write(fd, kNL, sizeof(kNL) - 1);
3542 PR_Close(fd);
3546 * Returns true if the startup cache file was successfully removed.
3547 * Returns false if file->Clone fails at any point (OOM) or if unable
3548 * to remove the startup cache file. Note in particular the return value
3549 * is unaffected by a failure to remove extensions.ini
3551 static bool RemoveComponentRegistries(nsIFile* aProfileDir,
3552 nsIFile* aLocalProfileDir,
3553 bool aRemoveEMFiles) {
3554 nsCOMPtr<nsIFile> file;
3555 aProfileDir->Clone(getter_AddRefs(file));
3556 if (!file) return false;
3558 if (aRemoveEMFiles) {
3559 file->SetNativeLeafName("extensions.ini"_ns);
3560 file->Remove(false);
3563 aLocalProfileDir->Clone(getter_AddRefs(file));
3564 if (!file) return false;
3566 file->AppendNative("startupCache"_ns);
3567 nsresult rv = file->Remove(true);
3568 return NS_SUCCEEDED(rv) || rv == NS_ERROR_FILE_NOT_FOUND;
3571 // When we first initialize the crash reporter we don't have a profile,
3572 // so we set the minidump path to $TEMP. Once we have a profile,
3573 // we set it to $PROFILE/minidumps, creating the directory
3574 // if needed.
3575 static void MakeOrSetMinidumpPath(nsIFile* profD) {
3576 nsCOMPtr<nsIFile> dumpD;
3577 profD->Clone(getter_AddRefs(dumpD));
3579 if (dumpD) {
3580 bool fileExists;
3581 // XXX: do some more error checking here
3582 dumpD->Append(u"minidumps"_ns);
3583 dumpD->Exists(&fileExists);
3584 if (!fileExists) {
3585 nsresult rv = dumpD->Create(nsIFile::DIRECTORY_TYPE, 0700);
3586 NS_ENSURE_SUCCESS_VOID(rv);
3589 nsAutoString pathStr;
3590 if (NS_SUCCEEDED(dumpD->GetPath(pathStr)))
3591 CrashReporter::SetMinidumpPath(pathStr);
3595 const XREAppData* gAppData = nullptr;
3598 * NSPR will search for the "nspr_use_zone_allocator" symbol throughout
3599 * the process and use it to determine whether the application defines its own
3600 * memory allocator or not.
3602 * Since most applications (e.g. Firefox and Thunderbird) don't use any special
3603 * allocators and therefore don't define this symbol, NSPR must search the
3604 * entire process, which reduces startup performance.
3606 * By defining the symbol here, we can avoid the wasted lookup and hopefully
3607 * improve startup performance.
3609 NS_VISIBILITY_DEFAULT PRBool nspr_use_zone_allocator = PR_FALSE;
3611 #ifdef CAIRO_HAS_DWRITE_FONT
3613 # include <dwrite.h>
3614 # include "nsWindowsHelpers.h"
3616 # ifdef DEBUG_DWRITE_STARTUP
3618 # define LOGREGISTRY(msg) LogRegistryEvent(msg)
3620 // for use when monitoring process
3621 static void LogRegistryEvent(const wchar_t* msg) {
3622 HKEY dummyKey;
3623 HRESULT hr;
3624 wchar_t buf[512];
3626 wsprintf(buf, L" log %s", msg);
3627 hr = RegOpenKeyEx(HKEY_LOCAL_MACHINE, buf, 0, KEY_READ, &dummyKey);
3628 if (SUCCEEDED(hr)) {
3629 RegCloseKey(dummyKey);
3632 # else
3634 # define LOGREGISTRY(msg)
3636 # endif
3638 static DWORD WINAPI InitDwriteBG(LPVOID lpdwThreadParam) {
3639 SetThreadPriority(GetCurrentThread(), THREAD_MODE_BACKGROUND_BEGIN);
3640 LOGREGISTRY(L"loading dwrite.dll");
3641 HMODULE dwdll = LoadLibrarySystem32(L"dwrite.dll");
3642 if (dwdll) {
3643 decltype(DWriteCreateFactory)* createDWriteFactory =
3644 (decltype(DWriteCreateFactory)*)GetProcAddress(dwdll,
3645 "DWriteCreateFactory");
3646 if (createDWriteFactory) {
3647 LOGREGISTRY(L"creating dwrite factory");
3648 IDWriteFactory* factory;
3649 HRESULT hr = createDWriteFactory(DWRITE_FACTORY_TYPE_SHARED,
3650 __uuidof(IDWriteFactory),
3651 reinterpret_cast<IUnknown**>(&factory));
3652 if (SUCCEEDED(hr)) {
3653 LOGREGISTRY(L"dwrite factory done");
3654 factory->Release();
3655 LOGREGISTRY(L"freed factory");
3656 } else {
3657 LOGREGISTRY(L"failed to create factory");
3661 SetThreadPriority(GetCurrentThread(), THREAD_MODE_BACKGROUND_END);
3662 return 0;
3664 #endif
3666 #include "GeckoProfiler.h"
3667 #include "ProfilerControl.h"
3669 // Encapsulates startup and shutdown state for XRE_main
3670 class XREMain {
3671 public:
3672 XREMain() = default;
3674 ~XREMain() {
3675 mScopedXPCOM = nullptr;
3676 mAppData = nullptr;
3679 int XRE_main(int argc, char* argv[], const BootstrapConfig& aConfig);
3680 int XRE_mainInit(bool* aExitFlag);
3681 int XRE_mainStartup(bool* aExitFlag);
3682 nsresult XRE_mainRun();
3684 bool CheckLastStartupWasCrash();
3686 nsCOMPtr<nsINativeAppSupport> mNativeApp;
3687 RefPtr<nsToolkitProfileService> mProfileSvc;
3688 nsCOMPtr<nsIFile> mProfD;
3689 nsCOMPtr<nsIFile> mProfLD;
3690 nsCOMPtr<nsIProfileLock> mProfileLock;
3691 #if defined(MOZ_HAS_REMOTE)
3692 RefPtr<nsRemoteService> mRemoteService;
3693 #endif
3695 UniquePtr<ScopedXPCOMStartup> mScopedXPCOM;
3696 UniquePtr<XREAppData> mAppData;
3698 nsXREDirProvider mDirProvider;
3700 #ifdef MOZ_WIDGET_GTK
3701 nsAutoCString mXDGActivationToken;
3702 nsAutoCString mDesktopStartupID;
3703 #endif
3705 bool mStartOffline = false;
3706 #if defined(MOZ_HAS_REMOTE)
3707 bool mDisableRemoteClient = false;
3708 bool mDisableRemoteServer = false;
3709 #endif
3712 #if defined(XP_UNIX) && !defined(ANDROID)
3713 static SmprintfPointer FormatUid(uid_t aId) {
3714 if (const auto pw = getpwuid(aId)) {
3715 return mozilla::Smprintf("%s", pw->pw_name);
3717 return mozilla::Smprintf("uid %d", static_cast<int>(aId));
3720 // Bug 1323302: refuse to run under sudo or similar.
3721 static bool CheckForUserMismatch() {
3722 static char const* const kVars[] = {
3723 "HOME",
3724 # ifdef MOZ_WIDGET_GTK
3725 "XDG_RUNTIME_DIR",
3726 # endif
3727 # ifdef MOZ_X11
3728 "XAUTHORITY",
3729 # endif
3732 const uid_t euid = geteuid();
3733 if (euid != 0) {
3734 // On Linux it's possible to have superuser capabilities with a
3735 // nonzero uid, but anyone who knows enough to make that happen
3736 // probably knows enough to debug the resulting problems.
3737 // Otherwise, a non-root user can't cause the problems we're
3738 // concerned about.
3739 return false;
3742 for (const auto var : kVars) {
3743 if (const auto path = PR_GetEnv(var)) {
3744 struct stat st;
3745 if (stat(path, &st) == 0) {
3746 if (st.st_uid != euid) {
3747 const auto owner = FormatUid(st.st_uid);
3748 Output(true,
3749 "Running " MOZ_APP_DISPLAYNAME
3750 " as root in a regular"
3751 " user's session is not supported. ($%s is %s which is"
3752 " owned by %s.)\n",
3753 var, path, owner.get());
3754 return true;
3759 return false;
3761 #else // !XP_UNIX || ANDROID
3762 static bool CheckForUserMismatch() { return false; }
3763 #endif
3765 void mozilla::startup::IncreaseDescriptorLimits() {
3766 #ifdef XP_UNIX
3767 // Increase the fd limit to accomodate IPC resources like shared memory.
3768 // See also the Darwin case in config/external/nspr/pr/moz.build
3769 static const rlim_t kFDs = 4096;
3770 struct rlimit rlim;
3772 if (getrlimit(RLIMIT_NOFILE, &rlim) != 0) {
3773 Output(false, "getrlimit: %s\n", strerror(errno));
3774 return;
3776 // Don't decrease the limit if it's already high enough, but don't
3777 // try to go over the hard limit. (RLIM_INFINITY isn't required to
3778 // be the numerically largest rlim_t, so don't assume that.)
3779 if (rlim.rlim_cur != RLIM_INFINITY && rlim.rlim_cur < kFDs &&
3780 rlim.rlim_cur < rlim.rlim_max) {
3781 if (rlim.rlim_max != RLIM_INFINITY && rlim.rlim_max < kFDs) {
3782 rlim.rlim_cur = rlim.rlim_max;
3783 } else {
3784 rlim.rlim_cur = kFDs;
3786 if (setrlimit(RLIMIT_NOFILE, &rlim) != 0) {
3787 Output(false, "setrlimit: %s\n", strerror(errno));
3790 #endif
3793 #ifdef XP_WIN
3795 static uint32_t GetMicrocodeVersionByVendor(HKEY key, DWORD upper,
3796 DWORD lower) {
3797 WCHAR data[13]; // The CPUID vendor string is 12 characters long plus null
3798 DWORD len = sizeof(data);
3799 DWORD vtype;
3801 if (RegQueryValueExW(key, L"VendorIdentifier", nullptr, &vtype,
3802 reinterpret_cast<LPBYTE>(data), &len) == ERROR_SUCCESS) {
3803 if (wcscmp(L"GenuineIntel", data) == 0) {
3804 // Intel reports the microcode version in the upper 32 bits of the MSR
3805 return upper;
3808 if (wcscmp(L"AuthenticAMD", data) == 0) {
3809 // AMD reports the microcode version in the lower 32 bits of the MSR
3810 return lower;
3813 // Unknown CPU vendor, return whatever half is non-zero
3814 return lower ? lower : upper;
3817 return 0; // No clue
3820 #endif // XP_WIN
3822 static void MaybeAddCPUMicrocodeCrashAnnotation() {
3823 #ifdef XP_WIN
3824 // Add CPU microcode version to the crash report as "CPUMicrocodeVersion".
3825 // It feels like this code may belong in nsSystemInfo instead.
3826 uint32_t cpuUpdateRevision = 0;
3827 HKEY key;
3828 static const WCHAR keyName[] =
3829 L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0";
3831 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, keyName, 0, KEY_QUERY_VALUE, &key) ==
3832 ERROR_SUCCESS) {
3833 DWORD updateRevision[2];
3834 DWORD len = sizeof(updateRevision);
3835 DWORD vtype;
3837 // Windows 7 uses "Update Signature", 8 uses "Update Revision".
3838 // For AMD CPUs, "CurrentPatchLevel" is sometimes used.
3839 // Take the first one we find.
3840 LPCWSTR choices[] = {L"Update Signature", L"Update Revision",
3841 L"CurrentPatchLevel"};
3842 for (const auto& oneChoice : choices) {
3843 if (RegQueryValueExW(key, oneChoice, nullptr, &vtype,
3844 reinterpret_cast<LPBYTE>(updateRevision),
3845 &len) == ERROR_SUCCESS) {
3846 if (vtype == REG_BINARY && len == sizeof(updateRevision)) {
3847 cpuUpdateRevision = GetMicrocodeVersionByVendor(
3848 key, updateRevision[1], updateRevision[0]);
3849 break;
3852 if (vtype == REG_DWORD && len == sizeof(updateRevision[0])) {
3853 cpuUpdateRevision = static_cast<int>(updateRevision[0]);
3854 break;
3860 if (cpuUpdateRevision > 0) {
3861 CrashReporter::AnnotateCrashReport(
3862 CrashReporter::Annotation::CPUMicrocodeVersion,
3863 nsPrintfCString("0x%" PRIx32, cpuUpdateRevision));
3865 #endif
3868 #if defined(MOZ_BACKGROUNDTASKS)
3869 static void SetupConsoleForBackgroundTask(
3870 const nsCString& aBackgroundTaskName) {
3871 // We do not suppress output on Windows because:
3872 // 1. Background task subprocesses launched via LaunchApp() does not attach to
3873 // the console.
3874 // 2. Suppressing output intermittently causes failures on when running
3875 // multiple tasks (see bug 1831631)
3876 # ifndef XP_WIN
3877 if (BackgroundTasks::IsNoOutputTaskName(aBackgroundTaskName) &&
3878 !CheckArg("attach-console") &&
3879 !EnvHasValue("MOZ_BACKGROUNDTASKS_IGNORE_NO_OUTPUT")) {
3880 // Suppress output, somewhat crudely. We need to suppress stderr as well
3881 // as stdout because assertions, of which there are many, write to stderr.
3882 Unused << freopen("/dev/null", "w", stdout);
3883 Unused << freopen("/dev/null", "w", stderr);
3884 return;
3886 # endif
3887 printf_stderr("*** You are running in background task mode. ***\n");
3889 #endif
3892 * XRE_mainInit - Initial setup and command line parameter processing.
3893 * Main() will exit early if either return value != 0 or if aExitFlag is
3894 * true.
3896 int XREMain::XRE_mainInit(bool* aExitFlag) {
3897 if (!aExitFlag) return 1;
3898 *aExitFlag = false;
3900 atexit(UnexpectedExit);
3901 auto expectedShutdown = mozilla::MakeScopeExit([&] { MozExpectedExit(); });
3903 StartupTimeline::Record(StartupTimeline::MAIN);
3905 if (CheckForUserMismatch()) {
3906 return 1;
3909 #ifdef XP_MACOSX
3910 mozilla::MacAutoreleasePool pool;
3912 DisableAppNap();
3913 #endif
3915 #ifdef MOZ_BACKGROUNDTASKS
3916 Maybe<nsCString> backgroundTask = Nothing();
3917 const char* backgroundTaskName = nullptr;
3918 if (ARG_FOUND ==
3919 CheckArg("backgroundtask", &backgroundTaskName, CheckArgFlag::None)) {
3920 backgroundTask = Some(backgroundTaskName);
3922 SetupConsoleForBackgroundTask(backgroundTask.ref());
3925 BackgroundTasks::Init(backgroundTask);
3926 #endif
3928 #ifndef ANDROID
3929 if (PR_GetEnv("MOZ_RUN_GTEST")
3930 # ifdef FUZZING
3931 || PR_GetEnv("FUZZER")
3932 # endif
3933 # ifdef MOZ_BACKGROUNDTASKS
3934 || BackgroundTasks::IsBackgroundTaskMode()
3935 # endif
3937 // Enable headless mode and assert that it worked, since gfxPlatform
3938 // uses a static bool set after the first call to `IsHeadless`.
3939 // Note: Android gtests seem to require an Activity and fail to start
3940 // with headless mode enabled.
3941 PR_SetEnv("MOZ_HEADLESS=1");
3942 MOZ_ASSERT(gfxPlatform::IsHeadless());
3944 #endif // ANDROID
3946 if (PR_GetEnv("MOZ_CHAOSMODE")) {
3947 ChaosFeature feature = ChaosFeature::Any;
3948 long featureInt = strtol(PR_GetEnv("MOZ_CHAOSMODE"), nullptr, 16);
3949 if (featureInt) {
3950 // NOTE: MOZ_CHAOSMODE=0 or a non-hex value maps to Any feature.
3951 feature = static_cast<ChaosFeature>(featureInt);
3953 ChaosMode::SetChaosFeature(feature);
3956 if (CheckArgExists("fxr")) {
3957 gFxREmbedded = true;
3960 if (ChaosMode::isActive(ChaosFeature::Any)) {
3961 printf_stderr(
3962 "*** You are running in chaos test mode. See ChaosMode.h. ***\n");
3965 if (CheckArg("headless") || CheckArgExists("screenshot")) {
3966 PR_SetEnv("MOZ_HEADLESS=1");
3969 if (gfxPlatform::IsHeadless()) {
3970 #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) || defined(XP_MACOSX)
3971 printf_stderr("*** You are running in headless mode.\n");
3972 #else
3973 Output(
3974 true,
3975 "Error: headless mode is not currently supported on this platform.\n");
3976 return 1;
3977 #endif
3979 #ifdef XP_MACOSX
3980 // To avoid taking focus when running in headless mode immediately
3981 // transition Firefox to a background application.
3982 ProcessSerialNumber psn = {0, kCurrentProcess};
3983 OSStatus transformStatus =
3984 TransformProcessType(&psn, kProcessTransformToBackgroundApplication);
3985 if (transformStatus != noErr) {
3986 NS_ERROR("Failed to make process a background application.");
3987 return 1;
3989 #endif
3992 gKioskMode = CheckArg("kiosk", nullptr, CheckArgFlag::None);
3993 const char* kioskMonitorNumber = nullptr;
3994 if (CheckArg("kiosk-monitor", &kioskMonitorNumber, CheckArgFlag::None)) {
3995 gKioskMode = true;
3996 gKioskMonitor = atoi(kioskMonitorNumber);
3999 gAllowContentAnalysis = CheckArg("allow-content-analysis", nullptr,
4000 CheckArgFlag::RemoveArg) == ARG_FOUND;
4002 nsresult rv;
4003 ArgResult ar;
4005 #ifdef DEBUG
4006 if (PR_GetEnv("XRE_MAIN_BREAK")) NS_BREAK();
4007 #endif
4009 mozilla::startup::IncreaseDescriptorLimits();
4011 SetupErrorHandling(gArgv[0]);
4013 #ifdef CAIRO_HAS_DWRITE_FONT
4015 // Bug 602792 - when DWriteCreateFactory is called the dwrite client dll
4016 // starts the FntCache service if it isn't already running (it's set
4017 // to manual startup by default in Windows 7 RTM). Subsequent DirectWrite
4018 // calls cause the IDWriteFactory object to communicate with the FntCache
4019 // service with a timeout; if there's no response after the timeout, the
4020 // DirectWrite client library will assume the service isn't around and do
4021 // manual font file I/O on _all_ system fonts. To avoid this, load the
4022 // dwrite library and create a factory as early as possible so that the
4023 // FntCache service is ready by the time it's needed.
4025 CreateThread(nullptr, 0, &InitDwriteBG, nullptr, 0, nullptr);
4027 #endif
4029 #ifdef XP_UNIX
4030 const char* home = PR_GetEnv("HOME");
4031 if (!home || !*home) {
4032 struct passwd* pw = getpwuid(geteuid());
4033 if (!pw || !pw->pw_dir) {
4034 Output(true, "Could not determine HOME directory");
4035 return 1;
4037 SaveWordToEnv("HOME", nsDependentCString(pw->pw_dir));
4039 #endif
4041 #ifdef MOZ_ACCESSIBILITY_ATK
4042 // Suppress atk-bridge init at startup, until mozilla accessibility is
4043 // initialized. This works after gnome 2.24.2.
4044 SaveToEnv("NO_AT_BRIDGE=1");
4045 #endif
4047 // Check for application.ini overrides
4048 const char* override = nullptr;
4049 ar = CheckArg("override", &override);
4050 if (ar == ARG_BAD) {
4051 Output(true, "Incorrect number of arguments passed to --override");
4052 return 1;
4054 if (ar == ARG_FOUND) {
4055 nsCOMPtr<nsIFile> overrideLF;
4056 rv = XRE_GetFileFromPath(override, getter_AddRefs(overrideLF));
4057 if (NS_FAILED(rv)) {
4058 Output(true, "Error: unrecognized override.ini path.\n");
4059 return 1;
4062 rv = XRE_ParseAppData(overrideLF, *mAppData);
4063 if (NS_FAILED(rv)) {
4064 Output(true, "Couldn't read override.ini");
4065 return 1;
4069 // Check sanity and correctness of app data.
4071 if (!mAppData->name) {
4072 Output(true, "Error: App:Name not specified in application.ini\n");
4073 return 1;
4075 if (!mAppData->buildID) {
4076 Output(true, "Error: App:BuildID not specified in application.ini\n");
4077 return 1;
4080 // XXX Originally ScopedLogging was here? Now it's in XRE_main above
4081 // XRE_mainInit.
4083 if (!mAppData->minVersion) {
4084 Output(true, "Error: Gecko:MinVersion not specified in application.ini\n");
4085 return 1;
4088 if (!mAppData->maxVersion) {
4089 // If no maxVersion is specified, we assume the app is only compatible
4090 // with the initial preview release. Do not increment this number ever!
4091 mAppData->maxVersion = "1.*";
4094 if (mozilla::Version(mAppData->minVersion) > gToolkitVersion ||
4095 mozilla::Version(mAppData->maxVersion) < gToolkitVersion) {
4096 Output(true,
4097 "Error: Platform version '%s' is not compatible with\n"
4098 "minVersion >= %s\nmaxVersion <= %s\n",
4099 (const char*)gToolkitVersion, (const char*)mAppData->minVersion,
4100 (const char*)mAppData->maxVersion);
4101 return 1;
4104 rv = mDirProvider.Initialize(mAppData->directory, mAppData->xreDirectory);
4105 if (NS_FAILED(rv)) return 1;
4107 if (EnvHasValue("MOZ_CRASHREPORTER")) {
4108 mAppData->flags |= NS_XRE_ENABLE_CRASH_REPORTER;
4111 nsCOMPtr<nsIFile> xreBinDirectory;
4112 xreBinDirectory = mDirProvider.GetGREBinDir();
4114 if ((mAppData->flags & NS_XRE_ENABLE_CRASH_REPORTER) &&
4115 NS_SUCCEEDED(CrashReporter::SetExceptionHandler(xreBinDirectory))) {
4116 nsCOMPtr<nsIFile> file;
4117 rv = nsXREDirProvider::GetUserAppDataDirectory(getter_AddRefs(file));
4118 if (NS_SUCCEEDED(rv)) {
4119 CrashReporter::SetUserAppDataDirectory(file);
4121 if (mAppData->crashReporterURL)
4122 CrashReporter::SetServerURL(
4123 nsDependentCString(mAppData->crashReporterURL));
4125 // We overwrite this once we finish starting up.
4126 CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::StartupCrash,
4127 true);
4129 // pass some basic info from the app data
4130 if (mAppData->vendor)
4131 CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::Vendor,
4132 nsDependentCString(mAppData->vendor));
4133 if (mAppData->name)
4134 CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::ProductName,
4135 nsDependentCString(mAppData->name));
4136 if (mAppData->ID)
4137 CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::ProductID,
4138 nsDependentCString(mAppData->ID));
4139 if (mAppData->version)
4140 CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::Version,
4141 nsDependentCString(mAppData->version));
4142 if (mAppData->buildID)
4143 CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::BuildID,
4144 nsDependentCString(mAppData->buildID));
4146 nsDependentCString releaseChannel(MOZ_STRINGIFY(MOZ_UPDATE_CHANNEL));
4147 CrashReporter::AnnotateCrashReport(
4148 CrashReporter::Annotation::ReleaseChannel, releaseChannel);
4150 #ifdef XP_WIN
4151 nsAutoString appInitDLLs;
4152 if (widget::WinUtils::GetAppInitDLLs(appInitDLLs)) {
4153 CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::AppInitDLLs,
4154 NS_ConvertUTF16toUTF8(appInitDLLs));
4157 nsString packageFamilyName = widget::WinUtils::GetPackageFamilyName();
4158 if (StringBeginsWith(packageFamilyName, u"Mozilla."_ns) ||
4159 StringBeginsWith(packageFamilyName, u"MozillaCorporation."_ns)) {
4160 CrashReporter::AnnotateCrashReport(
4161 CrashReporter::Annotation::WindowsPackageFamilyName,
4162 NS_ConvertUTF16toUTF8(packageFamilyName));
4164 #endif
4166 bool isBackgroundTaskMode = false;
4167 #ifdef MOZ_BACKGROUNDTASKS
4168 Maybe<nsCString> backgroundTasks = BackgroundTasks::GetBackgroundTasks();
4169 if (backgroundTasks.isSome()) {
4170 isBackgroundTaskMode = true;
4171 CrashReporter::AnnotateCrashReport(
4172 CrashReporter::Annotation::BackgroundTaskName, backgroundTasks.ref());
4174 #endif
4175 CrashReporter::AnnotateCrashReport(
4176 CrashReporter::Annotation::BackgroundTaskMode, isBackgroundTaskMode);
4178 CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::HeadlessMode,
4179 gfxPlatform::IsHeadless());
4181 CrashReporter::SetRestartArgs(gArgc, gArgv);
4183 // annotate other data (user id etc)
4184 nsCOMPtr<nsIFile> userAppDataDir;
4185 if (NS_SUCCEEDED(mDirProvider.GetUserAppDataDirectory(
4186 getter_AddRefs(userAppDataDir)))) {
4187 CrashReporter::SetupExtraData(userAppDataDir,
4188 nsDependentCString(mAppData->buildID));
4190 // see if we have a crashreporter-override.ini in the application
4191 // directory
4192 nsCOMPtr<nsIFile> overrideini;
4193 if (NS_SUCCEEDED(
4194 mDirProvider.GetAppDir()->Clone(getter_AddRefs(overrideini))) &&
4195 NS_SUCCEEDED(
4196 overrideini->AppendNative("crashreporter-override.ini"_ns))) {
4197 #ifdef XP_WIN
4198 nsAutoString overridePathW;
4199 overrideini->GetPath(overridePathW);
4200 NS_ConvertUTF16toUTF8 overridePath(overridePathW);
4201 #else
4202 nsAutoCString overridePath;
4203 overrideini->GetNativePath(overridePath);
4204 #endif
4206 SaveWordToEnv("MOZ_CRASHREPORTER_STRINGS_OVERRIDE", overridePath);
4209 } else {
4210 // We might have registered a runtime exception module very early in process
4211 // startup to catch early crashes. This is before we have access to ini file
4212 // data, so unregister here if it turns out the crash reporter is disabled.
4213 CrashReporter::UnregisterRuntimeExceptionModule();
4216 #if defined(MOZ_SANDBOX) && defined(XP_WIN)
4217 if (mAppData->sandboxBrokerServices) {
4218 SandboxBroker::Initialize(mAppData->sandboxBrokerServices);
4219 } else {
4220 # if defined(MOZ_SANDBOX)
4221 // If we're sandboxing content and we fail to initialize, then crashing here
4222 // seems like the sensible option.
4223 if (BrowserTabsRemoteAutostart()) {
4224 MOZ_CRASH("Failed to initialize broker services, can't continue.");
4226 # endif
4227 // Otherwise just warn for the moment, as most things will work.
4228 NS_WARNING(
4229 "Failed to initialize broker services, sandboxed processes will "
4230 "fail to start.");
4232 #endif
4234 #ifdef XP_MACOSX
4235 // Set up ability to respond to system (Apple) events. This must occur before
4236 // ProcessUpdates to ensure that links clicked in external applications aren't
4237 // lost when updates are pending.
4238 SetupMacApplicationDelegate(&gRestartedByOS);
4240 if (EnvHasValue("MOZ_LAUNCHED_CHILD")) {
4241 // This is needed, on relaunch, to force the OS to use the "Cocoa Dock
4242 // API". Otherwise the call to ReceiveNextEvent() below will make it
4243 // use the "Carbon Dock API". For more info see bmo bug 377166.
4244 EnsureUseCocoaDockAPI();
4246 // When the app relaunches, the original process exits. This causes
4247 // the dock tile to stop bouncing, lose the "running" triangle, and
4248 // if the tile does not permanently reside in the Dock, even disappear.
4249 // This can be confusing to the user, who is expecting the app to launch.
4250 // Calling ReceiveNextEvent without requesting any event is enough to
4251 // cause a dock tile for the child process to appear.
4252 const EventTypeSpec kFakeEventList[] = {{INT_MAX, INT_MAX}};
4253 EventRef event;
4254 ::ReceiveNextEvent(GetEventTypeCount(kFakeEventList), kFakeEventList,
4255 kEventDurationNoWait, false, &event);
4258 if (CheckArg("foreground")) {
4259 // The original process communicates that it was in the foreground by
4260 // adding this argument. This new process, which is taking over for
4261 // the old one, should make itself the active application.
4262 ProcessSerialNumber psn;
4263 if (::GetCurrentProcess(&psn) == noErr) ::SetFrontProcess(&psn);
4265 #endif
4267 SaveToEnv("MOZ_LAUNCHED_CHILD=");
4269 // On Windows, the -os-restarted command line switch lets us know when we are
4270 // restarted via RegisterApplicationRestart. May be used for other OSes later.
4271 if (CheckArg("os-restarted", nullptr, CheckArgFlag::RemoveArg) == ARG_FOUND) {
4272 gRestartedByOS = true;
4275 gRestartArgc = gArgc;
4276 gRestartArgv =
4277 (char**)malloc(sizeof(char*) * (gArgc + 1 + (override ? 2 : 0)));
4278 if (!gRestartArgv) {
4279 return 1;
4282 int i;
4283 for (i = 0; i < gArgc; ++i) {
4284 gRestartArgv[i] = gArgv[i];
4287 // Add the -override argument back (it is removed automatically be CheckArg)
4288 // if there is one
4289 if (override) {
4290 gRestartArgv[gRestartArgc++] = const_cast<char*>("-override");
4291 gRestartArgv[gRestartArgc++] = const_cast<char*>(override);
4294 gRestartArgv[gRestartArgc] = nullptr;
4296 Maybe<bool> safeModeRequested = IsSafeModeRequested(gArgc, gArgv);
4297 if (!safeModeRequested) {
4298 return 1;
4300 #ifdef MOZ_BACKGROUNDTASKS
4301 if (BackgroundTasks::IsBackgroundTaskMode()) {
4302 safeModeRequested = Some(false);
4304 // Remove the --backgroundtask arg now that it has been saved in
4305 // gRestartArgv.
4306 const char* tmpBackgroundTaskName = nullptr;
4307 Unused << CheckArg("backgroundtask", &tmpBackgroundTaskName,
4308 CheckArgFlag::RemoveArg);
4310 #endif
4312 gSafeMode = safeModeRequested.value();
4314 MaybeAddCPUMicrocodeCrashAnnotation();
4315 CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::SafeMode,
4316 gSafeMode);
4318 #if defined(MOZ_HAS_REMOTE)
4319 // Handle --no-remote and --new-instance command line arguments. Setup
4320 // the environment to better accommodate other components and various
4321 // restart scenarios.
4322 ar = CheckArg("no-remote");
4323 if (ar == ARG_FOUND || EnvHasValue("MOZ_NO_REMOTE")) {
4324 mDisableRemoteClient = true;
4325 mDisableRemoteServer = true;
4326 gRestartWithoutRemote = true;
4327 // We don't want to propagate MOZ_NO_REMOTE to potential child
4328 // process.
4329 SaveToEnv("MOZ_NO_REMOTE=");
4332 ar = CheckArg("new-instance");
4333 if (ar == ARG_FOUND || EnvHasValue("MOZ_NEW_INSTANCE")) {
4334 mDisableRemoteClient = true;
4336 #else
4337 // These arguments do nothing in platforms with no remoting support but we
4338 // should remove them from the command line anyway.
4339 CheckArg("no-remote");
4340 CheckArg("new-instance");
4341 #endif
4343 ar = CheckArg("offline");
4344 if (ar || EnvHasValue("XRE_START_OFFLINE")) {
4345 mStartOffline = true;
4348 // On Windows, to get working console arrangements so help/version/etc
4349 // print something, we need to initialize the native app support.
4350 rv = NS_CreateNativeAppSupport(getter_AddRefs(mNativeApp));
4351 if (NS_FAILED(rv)) return 1;
4353 // Handle --help, --full-version and --version command line arguments.
4354 // They should return quickly, so we deal with them here.
4355 if (CheckArg("h") || CheckArg("help") || CheckArg("?")) {
4356 DumpHelp();
4357 *aExitFlag = true;
4358 return 0;
4361 if (CheckArg("v") || CheckArg("version")) {
4362 DumpVersion();
4363 *aExitFlag = true;
4364 return 0;
4367 if (CheckArg("full-version")) {
4368 DumpFullVersion();
4369 *aExitFlag = true;
4370 return 0;
4373 rv = XRE_InitCommandLine(gArgc, gArgv);
4374 NS_ENSURE_SUCCESS(rv, 1);
4376 return 0;
4379 #if defined(XP_LINUX) && !defined(ANDROID)
4381 static void AnnotateLSBRelease(void*) {
4382 nsCString dist, desc, release, codename;
4383 if (widget::lsb::GetLSBRelease(dist, desc, release, codename)) {
4384 CrashReporter::AppendAppNotesToCrashReport(desc);
4388 #endif // defined(XP_LINUX) && !defined(ANDROID)
4390 #ifdef XP_WIN
4391 static void ReadAheadSystemDll(const wchar_t* dllName) {
4392 wchar_t dllPath[MAX_PATH];
4393 if (ConstructSystem32Path(dllName, dllPath, MAX_PATH)) {
4394 ReadAheadLib(dllPath);
4398 static void ReadAheadPackagedDll(const wchar_t* dllName,
4399 const wchar_t* aGREDir) {
4400 wchar_t dllPath[MAX_PATH];
4401 swprintf(dllPath, MAX_PATH, L"%s\\%s", aGREDir, dllName);
4402 ReadAheadLib(dllPath);
4405 static void PR_CALLBACK ReadAheadDlls_ThreadStart(void* arg) {
4406 UniquePtr<wchar_t[]> greDir(static_cast<wchar_t*>(arg));
4408 // In Bug 1628903, we investigated which DLLs we should prefetch in
4409 // order to reduce disk I/O and improve startup on Windows machines.
4410 // Our ultimate goal is to measure the impact of these improvements on
4411 // retention (see Bug 1640087). Before we place this within a pref,
4412 // we should ensure this feature only ships to the nightly channel
4413 // and monitor results from that subset.
4414 if (greDir) {
4415 // Prefetch the DLLs shipped with firefox
4416 ReadAheadPackagedDll(L"libegl.dll", greDir.get());
4417 ReadAheadPackagedDll(L"libGLESv2.dll", greDir.get());
4418 ReadAheadPackagedDll(L"nssckbi.dll", greDir.get());
4419 ReadAheadPackagedDll(L"freebl3.dll", greDir.get());
4420 ReadAheadPackagedDll(L"softokn3.dll", greDir.get());
4422 // Prefetch the system DLLs
4423 ReadAheadSystemDll(L"DWrite.dll");
4424 ReadAheadSystemDll(L"D3DCompiler_47.dll");
4425 } else {
4426 // Load DataExchange.dll and twinapi.appcore.dll for
4427 // nsWindow::EnableDragDrop
4428 ReadAheadSystemDll(L"DataExchange.dll");
4429 ReadAheadSystemDll(L"twinapi.appcore.dll");
4431 // Load twinapi.dll for WindowsUIUtils::UpdateTabletModeState
4432 ReadAheadSystemDll(L"twinapi.dll");
4434 // Load explorerframe.dll for WinTaskbar::Initialize
4435 ReadAheadSystemDll(L"ExplorerFrame.dll");
4437 // Load WinTypes.dll for nsOSHelperAppService::GetApplicationDescription
4438 ReadAheadSystemDll(L"WinTypes.dll");
4441 #endif
4443 #if defined(MOZ_UPDATER) && !defined(MOZ_WIDGET_ANDROID)
4444 enum struct ShouldNotProcessUpdatesReason {
4445 DevToolsLaunching,
4446 NotAnUpdatingTask,
4447 OtherInstanceRunning,
4448 FirstStartup
4451 const char* ShouldNotProcessUpdatesReasonAsString(
4452 ShouldNotProcessUpdatesReason aReason) {
4453 switch (aReason) {
4454 case ShouldNotProcessUpdatesReason::DevToolsLaunching:
4455 return "DevToolsLaunching";
4456 case ShouldNotProcessUpdatesReason::NotAnUpdatingTask:
4457 return "NotAnUpdatingTask";
4458 case ShouldNotProcessUpdatesReason::OtherInstanceRunning:
4459 return "OtherInstanceRunning";
4460 default:
4461 MOZ_CRASH("impossible value for ShouldNotProcessUpdatesReason");
4465 Maybe<ShouldNotProcessUpdatesReason> ShouldNotProcessUpdates(
4466 nsXREDirProvider& aDirProvider) {
4467 // Don't process updates when launched from the installer.
4468 // It's possible for a stale update to be present in the case of a paveover;
4469 // ignore it and leave the update service to discard it.
4470 if (ARG_FOUND == CheckArgExists("first-startup")) {
4471 NS_WARNING("ShouldNotProcessUpdates(): FirstStartup");
4472 return Some(ShouldNotProcessUpdatesReason::FirstStartup);
4475 // Do not process updates if we're launching devtools, as evidenced by
4476 // "--chrome ..." with the browser toolbox chrome document URL.
4478 // Keep this synchronized with the value of the same name in
4479 // devtools/client/framework/browser-toolbox/Launcher.sys.mjs. Or, for bonus
4480 // points, lift this value to nsIXulRuntime or similar, so that it can be
4481 // accessed in both locations. (The prefs service isn't available at this
4482 // point so the simplest manner of sharing the value is not available to us.)
4483 const char* BROWSER_TOOLBOX_WINDOW_URL =
4484 "chrome://devtools/content/framework/browser-toolbox/window.html";
4486 const char* chromeParam = nullptr;
4487 if (ARG_FOUND == CheckArg("chrome", &chromeParam, CheckArgFlag::None)) {
4488 if (!chromeParam || !strcmp(BROWSER_TOOLBOX_WINDOW_URL, chromeParam)) {
4489 NS_WARNING("ShouldNotProcessUpdates(): DevToolsLaunching");
4490 return Some(ShouldNotProcessUpdatesReason::DevToolsLaunching);
4494 # ifdef MOZ_BACKGROUNDTASKS
4495 // Do not process updates if we're running a background task mode and another
4496 // instance is already running. This avoids periodic maintenance updating
4497 // underneath a browsing session.
4498 Maybe<nsCString> backgroundTasks = BackgroundTasks::GetBackgroundTasks();
4499 if (backgroundTasks.isSome()) {
4500 // Only process updates for specific tasks: at this time, the
4501 // `backgroundupdate` task and the test-only `shouldprocessupdates` task.
4503 // Background tasks can be sparked by Firefox instances that are shutting
4504 // down, which can cause races between the task startup trying to update and
4505 // Firefox trying to invoke the updater. This happened when converting
4506 // `pingsender` to a background task, since it is launched to send pings at
4507 // shutdown: Bug 1736373.
4509 // We'd prefer to have this be a property of the task definition sibling to
4510 // `backgroundTaskTimeoutSec`, but when we reach this code we're well before
4511 // we can load the task JSM.
4512 if (!BackgroundTasks::IsUpdatingTaskName(backgroundTasks.ref())) {
4513 NS_WARNING("ShouldNotProcessUpdates(): NotAnUpdatingTask");
4514 return Some(ShouldNotProcessUpdatesReason::NotAnUpdatingTask);
4517 // At this point we have a dir provider but no XPCOM directory service. We
4518 // launch the update sync manager using that information so that it doesn't
4519 // need to ask for (and fail to find) the directory service.
4520 nsCOMPtr<nsIFile> anAppFile;
4521 bool persistent;
4522 nsresult rv = aDirProvider.GetFile(XRE_EXECUTABLE_FILE, &persistent,
4523 getter_AddRefs(anAppFile));
4524 if (NS_FAILED(rv) || !anAppFile) {
4525 // Strange, but not a reason to skip processing updates.
4526 return Nothing();
4529 auto updateSyncManager = new nsUpdateSyncManager(anAppFile);
4531 bool otherInstance = false;
4532 updateSyncManager->IsOtherInstanceRunning(&otherInstance);
4533 if (otherInstance) {
4534 NS_WARNING("ShouldNotProcessUpdates(): OtherInstanceRunning");
4535 return Some(ShouldNotProcessUpdatesReason::OtherInstanceRunning);
4538 # endif
4540 return Nothing();
4542 #endif
4544 namespace mozilla::startup {
4545 Result<nsCOMPtr<nsIFile>, nsresult> GetIncompleteStartupFile(nsIFile* aProfLD) {
4546 nsCOMPtr<nsIFile> crashFile;
4547 MOZ_TRY(aProfLD->Clone(getter_AddRefs(crashFile)));
4548 MOZ_TRY(crashFile->Append(FILE_STARTUP_INCOMPLETE));
4549 return std::move(crashFile);
4551 } // namespace mozilla::startup
4553 // Check whether the last startup attempt resulted in a crash or hang.
4554 // This is distinct from the definition of a startup crash from
4555 // nsAppStartup::TrackStartupCrashBegin.
4556 bool XREMain::CheckLastStartupWasCrash() {
4557 Result<nsCOMPtr<nsIFile>, nsresult> crashFile =
4558 GetIncompleteStartupFile(mProfLD);
4559 if (crashFile.isErr()) {
4560 return true;
4563 // Attempt to create the incomplete startup canary file. If the file already
4564 // exists, this fails, and we know the last startup was a crash. If it
4565 // doesn't already exist, it is created, and will be removed at the end of
4566 // the startup crash detection window.
4567 AutoFDClose fd;
4568 Unused << crashFile.inspect()->OpenNSPRFileDesc(
4569 PR_WRONLY | PR_CREATE_FILE | PR_EXCL, 0666, &fd.rwget());
4570 return !fd;
4574 * XRE_mainStartup - Initializes the profile and various other services.
4575 * Main() will exit early if either return value != 0 or if aExitFlag is
4576 * true.
4578 int XREMain::XRE_mainStartup(bool* aExitFlag) {
4579 nsresult rv;
4581 if (!aExitFlag) return 1;
4582 *aExitFlag = false;
4584 #ifdef XP_MACOSX
4585 mozilla::MacAutoreleasePool pool;
4586 #endif
4588 // Enable Telemetry IO Reporting on DEBUG, nightly and local builds,
4589 // but disable it on FUZZING builds and for ANDROID.
4590 #ifndef FUZZING
4591 # ifndef ANDROID
4592 # ifdef DEBUG
4593 mozilla::Telemetry::InitIOReporting(gAppData->xreDirectory);
4594 # else
4596 const char* releaseChannel = MOZ_STRINGIFY(MOZ_UPDATE_CHANNEL);
4597 if (strcmp(releaseChannel, "nightly") == 0 ||
4598 strcmp(releaseChannel, "default") == 0) {
4599 mozilla::Telemetry::InitIOReporting(gAppData->xreDirectory);
4602 # endif /* DEBUG */
4603 # endif /* ANDROID */
4604 #endif /* FUZZING */
4606 #if defined(XP_WIN)
4607 // Enable the HeapEnableTerminationOnCorruption exploit mitigation. We ignore
4608 // the return code because it always returns success, although it has no
4609 // effect on Windows older than XP SP3.
4610 HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);
4611 #endif /* XP_WIN */
4613 #ifdef MOZ_WIDGET_GTK
4614 // Stash startup token in owned memory because gtk_init will clear
4615 // DESKTOP_STARTUP_ID it.
4616 if (const char* v = PR_GetEnv("DESKTOP_STARTUP_ID")) {
4617 mDesktopStartupID.Assign(v);
4619 if (const char* v = PR_GetEnv("XDG_ACTIVATION_TOKEN")) {
4620 mXDGActivationToken.Assign(v);
4622 #endif
4624 #if defined(XP_WIN)
4626 // Save the shortcut path before lpTitle is replaced by an AUMID,
4627 // such as by WinTaskbar
4628 STARTUPINFOW si;
4629 GetStartupInfoW(&si);
4630 if (si.dwFlags & STARTF_TITLEISAPPID) {
4631 NS_WARNING("AUMID was already set, shortcut may have been lost.");
4632 } else if ((si.dwFlags & STARTF_TITLEISLINKNAME) && si.lpTitle) {
4633 gProcessStartupShortcut.Assign(si.lpTitle);
4636 #endif /* XP_WIN */
4638 #if defined(MOZ_WIDGET_GTK)
4639 // setup for private colormap. Ideally we'd like to do this
4640 // in nsAppShell::Create, but we need to get in before gtk
4641 // has been initialized to make sure everything is running
4642 // consistently.
4644 // Set program name to the one defined in application.ini.
4645 g_set_prgname(gAppData->remotingName);
4647 // Initialize GTK here for splash.
4649 # if defined(MOZ_WIDGET_GTK) && defined(MOZ_X11)
4650 // Disable XInput2 multidevice support due to focus bugginess.
4651 // See bugs 1182700, 1170342.
4652 // gdk_disable_multidevice() affects Gdk X11 backend only,
4653 // the multidevice support is always enabled on Wayland backend.
4654 const char* useXI2 = PR_GetEnv("MOZ_USE_XINPUT2");
4655 if (!useXI2 || (*useXI2 == '0')) gdk_disable_multidevice();
4656 # endif
4658 // Open the display ourselves instead of using gtk_init, so that we can
4659 // close it without fear that one day gtk might clean up the display it
4660 // opens.
4661 if (!gtk_parse_args(&gArgc, &gArgv)) return 1;
4662 #endif /* MOZ_WIDGET_GTK */
4664 #ifdef FUZZING
4665 if (PR_GetEnv("FUZZER")) {
4666 *aExitFlag = true;
4667 return mozilla::fuzzerRunner->Run(&gArgc, &gArgv);
4669 #endif
4671 if (PR_GetEnv("MOZ_RUN_GTEST")) {
4672 int result;
4673 #ifdef XP_WIN
4674 UseParentConsole();
4675 #endif
4676 // RunGTest will only be set if we're in xul-unit
4677 if (mozilla::RunGTest) {
4678 gIsGtest = true;
4679 result = mozilla::RunGTest(&gArgc, gArgv);
4680 gIsGtest = false;
4681 } else {
4682 result = 1;
4683 printf("TEST-UNEXPECTED-FAIL | gtest | Not compiled with enable-tests\n");
4685 *aExitFlag = true;
4686 return result;
4689 bool isBackgroundTaskMode = false;
4690 #ifdef MOZ_BACKGROUNDTASKS
4691 isBackgroundTaskMode = BackgroundTasks::IsBackgroundTaskMode();
4692 #endif
4694 #ifdef MOZ_HAS_REMOTE
4695 if (gfxPlatform::IsHeadless()) {
4696 mDisableRemoteClient = true;
4697 mDisableRemoteServer = true;
4699 #endif
4701 #ifdef MOZ_X11
4702 // Init X11 in thread-safe mode. Must be called prior to the first call to
4703 // XOpenDisplay (called inside gdk_display_open). This is a requirement for
4704 // off main tread compositing.
4705 if (!isBackgroundTaskMode && !gfxPlatform::IsHeadless()) {
4706 XInitThreads();
4708 #endif
4709 #if defined(MOZ_WIDGET_GTK)
4710 if (!isBackgroundTaskMode && !gfxPlatform::IsHeadless()) {
4711 const char* display_name = nullptr;
4712 bool saveDisplayArg = false;
4714 // display_name is owned by gdk.
4715 display_name = gdk_get_display_arg_name();
4716 // if --display argument is given make sure it's
4717 // also passed to ContentChild::Init() by MOZ_GDK_DISPLAY.
4718 if (display_name) {
4719 SaveWordToEnv("MOZ_GDK_DISPLAY", nsDependentCString(display_name));
4720 saveDisplayArg = true;
4723 bool waylandEnabled = IsWaylandEnabled();
4724 // On Wayland disabled builds read X11 DISPLAY env exclusively
4725 // and don't care about different displays.
4726 if (!waylandEnabled && !display_name) {
4727 display_name = PR_GetEnv("DISPLAY");
4728 if (!display_name) {
4729 PR_fprintf(PR_STDERR,
4730 "Error: no DISPLAY environment variable specified\n");
4731 return 1;
4735 if (display_name) {
4736 GdkDisplay* disp = gdk_display_open(display_name);
4737 if (!disp) {
4738 PR_fprintf(PR_STDERR, "Error: cannot open display: %s\n", display_name);
4739 return 1;
4741 if (saveDisplayArg) {
4742 if (GdkIsX11Display(disp)) {
4743 SaveWordToEnv("DISPLAY", nsDependentCString(display_name));
4745 # ifdef MOZ_WAYLAND
4746 else if (GdkIsWaylandDisplay(disp)) {
4747 SaveWordToEnv("WAYLAND_DISPLAY", nsDependentCString(display_name));
4749 # endif
4752 # ifdef MOZ_WIDGET_GTK
4753 else {
4754 gdk_display_manager_open_display(gdk_display_manager_get(), nullptr);
4756 # endif
4757 // Check that Wayland only and X11 only builds
4758 // use appropriate displays.
4759 # if defined(MOZ_WAYLAND) && !defined(MOZ_X11)
4760 if (!GdkIsWaylandDisplay()) {
4761 Output(true, "Wayland only build is missig Wayland display!\n");
4763 # endif
4764 # if !defined(MOZ_WAYLAND) && defined(MOZ_X11)
4765 if (!GdkIsX11Display()) {
4766 Output(true, "X11 only build is missig X11 display!\n");
4768 # endif
4770 #endif
4771 #if defined(MOZ_HAS_REMOTE)
4772 // handle --remote now that xpcom is fired up
4773 mRemoteService = new nsRemoteService(gAppData->remotingName);
4774 if (mRemoteService && !mDisableRemoteServer) {
4775 mRemoteService->LockStartup();
4776 gRemoteService = mRemoteService;
4778 #endif
4779 #if defined(MOZ_WIDGET_GTK)
4780 g_set_application_name(mAppData->name);
4782 #endif /* defined(MOZ_WIDGET_GTK) */
4783 #ifdef MOZ_X11
4784 // Do this after initializing GDK, or GDK will install its own handler.
4785 XRE_InstallX11ErrorHandler();
4786 #endif
4788 // Call the code to install our handler
4789 #ifdef MOZ_JPROF
4790 setupProfilingStuff();
4791 #endif
4793 bool canRun = false;
4794 rv = mNativeApp->Start(&canRun);
4795 if (NS_FAILED(rv) || !canRun) {
4796 return 1;
4799 #ifdef MOZ_WIDGET_GTK
4800 // startup token might be cleared now, we recover it in case we need a
4801 // restart.
4802 if (!mDesktopStartupID.IsEmpty()) {
4803 // Leak it with extreme prejudice!
4804 PR_SetEnv(ToNewCString("DESKTOP_STARTUP_ID="_ns + mDesktopStartupID));
4807 if (!mXDGActivationToken.IsEmpty()) {
4808 // Leak it with extreme prejudice!
4809 PR_SetEnv(ToNewCString("XDG_ACTIVATION_TOKEN="_ns + mXDGActivationToken));
4811 #endif
4813 // Support exiting early for testing startup sequence. Bug 1360493
4814 if (CheckArg("test-launch-without-hang")) {
4815 *aExitFlag = true;
4816 return 0;
4819 mProfileSvc = NS_GetToolkitProfileService();
4820 if (!mProfileSvc) {
4821 // We failed to choose or create profile - notify user and quit
4822 ProfileMissingDialog(mNativeApp);
4823 return 1;
4826 bool wasDefaultSelection;
4827 nsCOMPtr<nsIToolkitProfile> profile;
4828 rv = SelectProfile(mProfileSvc, mNativeApp, getter_AddRefs(mProfD),
4829 getter_AddRefs(mProfLD), getter_AddRefs(profile),
4830 &wasDefaultSelection);
4831 if (rv == NS_ERROR_LAUNCHED_CHILD_PROCESS || rv == NS_ERROR_ABORT) {
4832 *aExitFlag = true;
4833 return 0;
4836 if (NS_FAILED(rv)) {
4837 // We failed to choose or create profile - notify user and quit
4838 ProfileMissingDialog(mNativeApp);
4839 return 1;
4842 #if defined(MOZ_HAS_REMOTE)
4843 if (mRemoteService) {
4844 // We want a unique profile name to identify the remote instance.
4845 nsCString profileName;
4846 if (profile) {
4847 rv = profile->GetName(profileName);
4849 if (!profile || NS_FAILED(rv) || profileName.IsEmpty()) {
4850 // Couldn't get a name from the profile. Use the directory name?
4851 nsString leafName;
4852 rv = mProfD->GetLeafName(leafName);
4853 if (NS_SUCCEEDED(rv)) {
4854 CopyUTF16toUTF8(leafName, profileName);
4858 mRemoteService->SetProfile(profileName);
4860 if (!mDisableRemoteClient) {
4861 // Try to remote the entire command line. If this fails, start up
4862 // normally.
4863 # ifdef MOZ_WIDGET_GTK
4864 const auto& startupToken =
4865 GdkIsWaylandDisplay() ? mXDGActivationToken : mDesktopStartupID;
4866 # else
4867 const nsCString startupToken;
4868 # endif
4869 RemoteResult rr = mRemoteService->StartClient(
4870 startupToken.IsEmpty() ? nullptr : startupToken.get());
4871 if (rr == REMOTE_FOUND) {
4872 *aExitFlag = true;
4873 mRemoteService->UnlockStartup();
4874 return 0;
4876 if (rr == REMOTE_ARG_BAD) {
4877 mRemoteService->UnlockStartup();
4878 return 1;
4882 #endif
4884 #if defined(MOZ_UPDATER) && !defined(MOZ_WIDGET_ANDROID)
4885 # ifdef XP_WIN
4887 // When automatically restarting for a staged background update
4888 // we want the child process to wait here so that the updater
4889 // does not register two instances running and use that as a
4890 // reason to not process updates. This function requires having
4891 // -restart-pid <param> in the command line to function properly.
4892 // Ensure we keep -restart-pid if we are running tests
4893 if (ARG_FOUND == CheckArgExists("restart-pid") &&
4894 !CheckArg("test-only-automatic-restart-no-wait")) {
4895 // We're not testing and can safely remove it now and read the pid.
4896 const char* restartPidString = nullptr;
4897 CheckArg("restart-pid", &restartPidString, CheckArgFlag::RemoveArg);
4898 // pid should be first parameter following -restart-pid.
4899 uint32_t pid = nsDependentCString(restartPidString).ToInteger(&rv, 10U);
4900 if (NS_SUCCEEDED(rv) && pid > 0) {
4901 printf_stderr(
4902 "*** MaybeWaitForProcessExit: launched pidDWORD = %u ***\n", pid);
4903 RefPtr<nsUpdateProcessor> updater = new nsUpdateProcessor();
4904 if (NS_FAILED(
4905 updater->WaitForProcessExit(pid, MAYBE_WAIT_TIMEOUT_MS))) {
4906 NS_WARNING("Failed to MaybeWaitForProcessExit.");
4908 } else {
4909 NS_WARNING("Failed to parse pid from -restart-pid.");
4913 # endif
4914 Maybe<ShouldNotProcessUpdatesReason> shouldNotProcessUpdatesReason =
4915 ShouldNotProcessUpdates(mDirProvider);
4916 if (shouldNotProcessUpdatesReason.isNothing()) {
4917 // Check for and process any available updates
4918 nsCOMPtr<nsIFile> updRoot;
4919 bool persistent;
4920 rv = mDirProvider.GetFile(XRE_UPDATE_ROOT_DIR, &persistent,
4921 getter_AddRefs(updRoot));
4922 // XRE_UPDATE_ROOT_DIR may fail. Fallback to appDir if failed
4923 if (NS_FAILED(rv)) {
4924 updRoot = mDirProvider.GetAppDir();
4927 // If the MOZ_TEST_PROCESS_UPDATES environment variable already exists, then
4928 // we are being called from the callback application.
4929 if (EnvHasValue("MOZ_TEST_PROCESS_UPDATES")) {
4930 // If the caller has asked us to log our arguments, do so. This is used
4931 // to make sure that the maintenance service successfully launches the
4932 // callback application.
4933 const char* logFile = nullptr;
4934 if (ARG_FOUND == CheckArg("dump-args", &logFile)) {
4935 FILE* logFP = fopen(logFile, "wb");
4936 if (logFP) {
4937 for (int i = 1; i < gRestartArgc; ++i) {
4938 fprintf(logFP, "%s\n", gRestartArgv[i]);
4940 fclose(logFP);
4943 *aExitFlag = true;
4944 return 0;
4947 // Support for processing an update and exiting. The
4948 // MOZ_TEST_PROCESS_UPDATES environment variable will be part of the
4949 // updater's environment and the application that is relaunched by the
4950 // updater. When the application is relaunched by the updater it will be
4951 // removed below and the application will exit.
4952 if (CheckArg("test-process-updates")) {
4953 SaveToEnv("MOZ_TEST_PROCESS_UPDATES=1");
4955 nsCOMPtr<nsIFile> exeFile, exeDir;
4956 rv = mDirProvider.GetFile(XRE_EXECUTABLE_FILE, &persistent,
4957 getter_AddRefs(exeFile));
4958 NS_ENSURE_SUCCESS(rv, 1);
4959 rv = exeFile->GetParent(getter_AddRefs(exeDir));
4960 NS_ENSURE_SUCCESS(rv, 1);
4961 ProcessUpdates(mDirProvider.GetGREDir(), exeDir, updRoot, gRestartArgc,
4962 gRestartArgv, mAppData->version);
4963 if (EnvHasValue("MOZ_TEST_PROCESS_UPDATES")) {
4964 SaveToEnv("MOZ_TEST_PROCESS_UPDATES=");
4965 *aExitFlag = true;
4966 return 0;
4968 } else {
4969 if (CheckArg("test-process-updates") ||
4970 EnvHasValue("MOZ_TEST_PROCESS_UPDATES")) {
4971 // Support for testing *not* processing an update. The launched process
4972 // can witness this environment variable and conclude that its runtime
4973 // environment resulted in not processing updates.
4975 SaveToEnv(nsPrintfCString(
4976 "MOZ_TEST_PROCESS_UPDATES=ShouldNotProcessUpdates(): %s",
4977 ShouldNotProcessUpdatesReasonAsString(
4978 shouldNotProcessUpdatesReason.value()))
4979 .get());
4982 #endif
4984 // We now know there is no existing instance using the selected profile. If
4985 // the profile wasn't selected by specific command line arguments and the
4986 // user has chosen to show the profile manager on startup then do that.
4987 if (wasDefaultSelection) {
4988 bool useSelectedProfile;
4989 rv = mProfileSvc->GetStartWithLastProfile(&useSelectedProfile);
4990 NS_ENSURE_SUCCESS(rv, 1);
4992 if (!useSelectedProfile) {
4993 rv = ShowProfileManager(mProfileSvc, mNativeApp);
4994 if (rv == NS_ERROR_LAUNCHED_CHILD_PROCESS || rv == NS_ERROR_ABORT) {
4995 *aExitFlag = true;
4996 return 0;
4998 if (NS_FAILED(rv)) {
4999 return 1;
5004 // We always want to lock the profile even if we're actually going to reset
5005 // it later.
5006 rv = LockProfile(mNativeApp, mProfD, mProfLD, profile,
5007 getter_AddRefs(mProfileLock));
5008 if (rv == NS_ERROR_LAUNCHED_CHILD_PROCESS || rv == NS_ERROR_ABORT) {
5009 *aExitFlag = true;
5010 return 0;
5011 } else if (NS_FAILED(rv)) {
5012 return 1;
5015 if (gDoProfileReset) {
5016 if (EnvHasValue("MOZ_RESET_PROFILE_RESTART")) {
5017 SaveToEnv("MOZ_RESET_PROFILE_RESTART=");
5018 // We only want to restore the previous session if the profile refresh was
5019 // triggered by user. And if it was a user-triggered profile refresh
5020 // through, say, the safeMode dialog or the troubleshooting page, the
5021 // MOZ_RESET_PROFILE_RESTART env variable would be set. Hence we set
5022 // MOZ_RESET_PROFILE_MIGRATE_SESSION here so that Firefox profile migrator
5023 // would migrate old session data later.
5024 SaveToEnv("MOZ_RESET_PROFILE_MIGRATE_SESSION=1");
5026 // Unlock the source profile.
5027 mProfileLock->Unlock();
5029 // If we're resetting a profile, create a new one and use it to startup.
5030 gResetOldProfile = profile;
5031 rv = mProfileSvc->CreateResetProfile(getter_AddRefs(profile));
5032 if (NS_SUCCEEDED(rv)) {
5033 rv = profile->GetRootDir(getter_AddRefs(mProfD));
5034 NS_ENSURE_SUCCESS(rv, 1);
5035 SaveFileToEnv("XRE_PROFILE_PATH", mProfD);
5037 rv = profile->GetLocalDir(getter_AddRefs(mProfLD));
5038 NS_ENSURE_SUCCESS(rv, 1);
5039 SaveFileToEnv("XRE_PROFILE_LOCAL_PATH", mProfLD);
5041 // Lock the new profile
5042 rv = LockProfile(mNativeApp, mProfD, mProfLD, profile,
5043 getter_AddRefs(mProfileLock));
5044 if (rv == NS_ERROR_LAUNCHED_CHILD_PROCESS || rv == NS_ERROR_ABORT) {
5045 *aExitFlag = true;
5046 return 0;
5047 } else if (NS_FAILED(rv)) {
5048 return 1;
5050 } else {
5051 NS_WARNING("Profile reset failed.");
5052 return 1;
5056 gProfileLock = mProfileLock;
5058 nsAutoCString version;
5059 BuildVersion(version);
5061 #ifdef TARGET_OS_ABI
5062 constexpr auto osABI = nsLiteralCString{TARGET_OS_ABI};
5063 #else
5064 // No TARGET_XPCOM_ABI, but at least the OS is known
5065 constexpr auto osABI = nsLiteralCString{OS_TARGET "_UNKNOWN"};
5066 #endif
5068 // Check for version compatibility with the last version of the app this
5069 // profile was started with. The format of the version stamp is defined
5070 // by the BuildVersion function.
5071 // Also check to see if something has happened to invalidate our
5072 // fastload caches, like an app upgrade.
5074 // If we see .purgecaches, that means someone did a make.
5075 // Re-register components to catch potential changes.
5076 nsCOMPtr<nsIFile> flagFile;
5077 if (mAppData->directory) {
5078 Unused << mAppData->directory->Clone(getter_AddRefs(flagFile));
5080 if (flagFile) {
5081 flagFile->AppendNative(FILE_INVALIDATE_CACHES);
5084 bool cachesOK;
5085 bool isDowngrade;
5086 nsCString lastVersion;
5087 bool versionOK = CheckCompatibility(
5088 mProfD, version, osABI, mDirProvider.GetGREDir(), mAppData->directory,
5089 flagFile, &cachesOK, &isDowngrade, lastVersion);
5091 MOZ_RELEASE_ASSERT(!cachesOK || lastVersion.Equals(version),
5092 "Caches cannot be good if the version has changed.");
5094 #ifdef MOZ_BLOCK_PROFILE_DOWNGRADE
5095 // The argument check must come first so the argument is always removed from
5096 // the command line regardless of whether this is a downgrade or not.
5097 if (!CheckArg("allow-downgrade") && isDowngrade &&
5098 !EnvHasValue("MOZ_ALLOW_DOWNGRADE")) {
5099 rv = CheckDowngrade(mProfD, mNativeApp, mProfileSvc, lastVersion);
5100 if (rv == NS_ERROR_LAUNCHED_CHILD_PROCESS || rv == NS_ERROR_ABORT) {
5101 *aExitFlag = true;
5102 return 0;
5105 #endif
5107 rv = mDirProvider.SetProfile(mProfD, mProfLD);
5108 NS_ENSURE_SUCCESS(rv, 1);
5110 //////////////////////// NOW WE HAVE A PROFILE ////////////////////////
5112 mozilla::Telemetry::SetProfileDir(mProfD);
5114 if (mAppData->flags & NS_XRE_ENABLE_CRASH_REPORTER) {
5115 MakeOrSetMinidumpPath(mProfD);
5118 CrashReporter::SetProfileDirectory(mProfD);
5120 #ifdef MOZ_ASAN_REPORTER
5121 // In ASan reporter builds, we need to set ASan's log_path as early as
5122 // possible, so it dumps its errors into files there instead of using
5123 // the default stderr location. Since this is crucial for ASan reporter
5124 // to work at all (and we don't want people to use a non-functional
5125 // ASan reporter build), all failures while setting log_path are fatal.
5126 setASanReporterPath(mProfD);
5128 // Export to env for child processes
5129 SaveFileToEnv("ASAN_REPORTER_PATH", mProfD);
5130 #endif
5132 bool lastStartupWasCrash = CheckLastStartupWasCrash();
5134 CrashReporter::AnnotateCrashReport(
5135 CrashReporter::Annotation::LastStartupWasCrash, lastStartupWasCrash);
5137 if (CheckArg("purgecaches") || PR_GetEnv("MOZ_PURGE_CACHES") ||
5138 lastStartupWasCrash || gSafeMode) {
5139 cachesOK = false;
5142 CrashReporter::AnnotateCrashReport(
5143 CrashReporter::Annotation::StartupCacheValid, cachesOK && versionOK);
5145 // Every time a profile is loaded by a build with a different version,
5146 // it updates the compatibility.ini file saying what version last wrote
5147 // the fastload caches. On subsequent launches if the version matches,
5148 // there is no need for re-registration. If the user loads the same
5149 // profile in different builds the component registry must be
5150 // re-generated to prevent mysterious component loading failures.
5152 bool startupCacheValid = true;
5154 if (!cachesOK || !versionOK) {
5155 QuotaManager::InvalidateQuotaCache();
5157 startupCacheValid = RemoveComponentRegistries(mProfD, mProfLD, false);
5159 // Rewrite compatibility.ini to match the current build. The next run
5160 // should attempt to invalidate the caches if either this run is safe mode
5161 // or the attempt to invalidate the caches this time failed.
5162 WriteVersion(mProfD, version, osABI, mDirProvider.GetGREDir(),
5163 mAppData->directory, gSafeMode || !startupCacheValid);
5166 if (!startupCacheValid) StartupCache::IgnoreDiskCache();
5168 if (flagFile) {
5169 flagFile->Remove(true);
5172 // Flush any pending page load events.
5173 mozilla::glean_pings::Pageload.Submit("startup"_ns);
5175 if (!isBackgroundTaskMode) {
5176 #ifdef USE_GLX_TEST
5177 GfxInfo::FireGLXTestProcess();
5178 #endif
5179 #ifdef MOZ_WAYLAND
5180 // Make sure we have wayland connection for main thread.
5181 // It's used as template to create display connections
5182 // for different threads.
5183 if (IsWaylandEnabled()) {
5184 MOZ_UNUSED(WaylandDisplayGet());
5186 #endif
5187 #ifdef MOZ_WIDGET_GTK
5188 nsAppShell::InstallTermSignalHandler();
5189 #endif
5192 return 0;
5195 #if defined(MOZ_SANDBOX)
5196 void AddSandboxAnnotations() {
5198 // Include the sandbox content level, regardless of platform
5199 int level = GetEffectiveContentSandboxLevel();
5201 nsAutoCString levelString;
5202 levelString.AppendInt(level);
5204 CrashReporter::AnnotateCrashReport(
5205 CrashReporter::Annotation::ContentSandboxLevel, levelString);
5209 int level = GetEffectiveGpuSandboxLevel();
5211 nsAutoCString levelString;
5212 levelString.AppendInt(level);
5214 CrashReporter::AnnotateCrashReport(
5215 CrashReporter::Annotation::GpuSandboxLevel, levelString);
5218 // Include whether or not this instance is capable of content sandboxing
5219 bool sandboxCapable = false;
5221 # if defined(XP_WIN)
5222 // All supported Windows versions support some level of content sandboxing
5223 sandboxCapable = true;
5224 # elif defined(XP_MACOSX)
5225 // All supported OS X versions are capable
5226 sandboxCapable = true;
5227 # elif defined(XP_LINUX)
5228 sandboxCapable = SandboxInfo::Get().CanSandboxContent();
5229 # elif defined(__OpenBSD__)
5230 sandboxCapable = true;
5231 StartOpenBSDSandbox(GeckoProcessType_Default);
5232 # endif
5234 CrashReporter::AnnotateCrashReport(
5235 CrashReporter::Annotation::ContentSandboxCapable, sandboxCapable);
5237 #endif /* MOZ_SANDBOX */
5240 * XRE_mainRun - Command line startup, profile migration, and
5241 * the calling of appStartup->Run().
5243 nsresult XREMain::XRE_mainRun() {
5244 nsresult rv = NS_OK;
5245 NS_ASSERTION(mScopedXPCOM, "Scoped xpcom not initialized.");
5247 #if defined(XP_WIN)
5248 RefPtr<mozilla::DllServices> dllServices(mozilla::DllServices::Get());
5249 dllServices->StartUntrustedModulesProcessor(false);
5250 auto dllServicesDisable =
5251 MakeScopeExit([&dllServices]() { dllServices->DisableFull(); });
5253 mozilla::mscom::InitProfilerMarkers();
5254 #endif // defined(XP_WIN)
5256 // We need the appStartup pointer to span multiple scopes, so we declare
5257 // it here.
5258 nsCOMPtr<nsIAppStartup> appStartup;
5259 // Ditto with the command line.
5260 nsCOMPtr<nsICommandLineRunner> cmdLine;
5263 #ifdef XP_MACOSX
5264 // In this scope, create an autorelease pool that will leave scope with
5265 // it just before entering our event loop.
5266 mozilla::MacAutoreleasePool pool;
5267 #endif
5269 rv = mScopedXPCOM->SetWindowCreator(mNativeApp);
5270 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
5272 // tell the crash reporter to also send the release channel
5273 nsCOMPtr<nsIPrefService> prefs =
5274 do_GetService("@mozilla.org/preferences-service;1", &rv);
5275 if (NS_SUCCEEDED(rv)) {
5276 nsCOMPtr<nsIPrefBranch> defaultPrefBranch;
5277 rv = prefs->GetDefaultBranch(nullptr, getter_AddRefs(defaultPrefBranch));
5279 if (NS_SUCCEEDED(rv)) {
5280 nsAutoCString sval;
5281 rv = defaultPrefBranch->GetCharPref("app.update.channel", sval);
5282 if (NS_SUCCEEDED(rv)) {
5283 CrashReporter::AnnotateCrashReport(
5284 CrashReporter::Annotation::ReleaseChannel, sval);
5288 // Needs to be set after xpcom initialization.
5289 bool includeContextHeap = Preferences::GetBool(
5290 "toolkit.crashreporter.include_context_heap", false);
5291 CrashReporter::SetIncludeContextHeap(includeContextHeap);
5293 #if defined(XP_LINUX) && !defined(ANDROID)
5294 PR_CreateThread(PR_USER_THREAD, AnnotateLSBRelease, 0, PR_PRIORITY_LOW,
5295 PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD, 0);
5296 #endif
5298 if (mStartOffline) {
5299 nsCOMPtr<nsIIOService> io(
5300 do_GetService("@mozilla.org/network/io-service;1"));
5301 NS_ENSURE_TRUE(io, NS_ERROR_FAILURE);
5302 io->SetManageOfflineStatus(false);
5303 io->SetOffline(true);
5306 #ifdef XP_WIN
5307 mozilla::DllPrefetchExperimentRegistryInfo prefetchRegInfo;
5308 mozilla::AlteredDllPrefetchMode dllPrefetchMode =
5309 prefetchRegInfo.GetAlteredDllPrefetchMode();
5311 if (!PR_GetEnv("XRE_NO_DLL_READAHEAD") &&
5312 dllPrefetchMode != mozilla::AlteredDllPrefetchMode::NoPrefetch) {
5313 nsCOMPtr<nsIFile> greDir = mDirProvider.GetGREDir();
5314 nsAutoString path;
5315 rv = greDir->GetPath(path);
5316 if (NS_SUCCEEDED(rv)) {
5317 PRThread* readAheadThread;
5318 wchar_t* pathRaw;
5320 // We use the presence of a path argument inside the thread to determine
5321 // which list of Dlls to use. The old list does not need access to the
5322 // GRE dir, so the path argument is set to a null pointer.
5323 if (dllPrefetchMode ==
5324 mozilla::AlteredDllPrefetchMode::OptimizedPrefetch) {
5325 pathRaw = new wchar_t[MAX_PATH];
5326 wcscpy_s(pathRaw, MAX_PATH, path.get());
5327 } else {
5328 pathRaw = nullptr;
5330 readAheadThread = PR_CreateThread(
5331 PR_USER_THREAD, ReadAheadDlls_ThreadStart, (void*)pathRaw,
5332 PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD, 0);
5333 if (readAheadThread == NULL) {
5334 delete[] pathRaw;
5338 #endif
5340 if (gDoMigration) {
5341 nsCOMPtr<nsIFile> file;
5342 mDirProvider.GetAppDir()->Clone(getter_AddRefs(file));
5343 file->AppendNative("override.ini"_ns);
5344 nsINIParser parser;
5345 nsresult rv = parser.Init(file);
5346 // if override.ini doesn't exist, also check for distribution.ini
5347 if (NS_FAILED(rv)) {
5348 bool persistent;
5349 mDirProvider.GetFile(XRE_APP_DISTRIBUTION_DIR, &persistent,
5350 getter_AddRefs(file));
5351 file->AppendNative("distribution.ini"_ns);
5352 rv = parser.Init(file);
5354 if (NS_SUCCEEDED(rv)) {
5355 nsAutoCString buf;
5356 rv = parser.GetString("XRE", "EnableProfileMigrator", buf);
5357 if (NS_SUCCEEDED(rv)) {
5358 if (buf[0] == '0' || buf[0] == 'f' || buf[0] == 'F') {
5359 gDoMigration = false;
5365 // We'd like to initialize the JSContext *after* reading the user prefs.
5366 // Unfortunately that's not possible if we have to do profile migration
5367 // because that requires us to execute JS before reading user prefs.
5368 // Restarting the browser after profile migration would fix this. See
5369 // bug 1592523.
5370 bool initializedJSContext = false;
5373 // Profile Migration
5374 if (mAppData->flags & NS_XRE_ENABLE_PROFILE_MIGRATOR && gDoMigration) {
5375 gDoMigration = false;
5377 xpc::InitializeJSContext();
5378 initializedJSContext = true;
5380 nsCOMPtr<nsIProfileMigrator> pm(
5381 do_CreateInstance(NS_PROFILEMIGRATOR_CONTRACTID));
5382 if (pm) {
5383 nsAutoCString aKey;
5384 nsAutoCString aName;
5385 if (gDoProfileReset) {
5386 // Automatically migrate from the current application if we just
5387 // reset the profile.
5388 aKey = MOZ_APP_NAME;
5389 gResetOldProfile->GetName(aName);
5391 pm->Migrate(&mDirProvider, aKey, aName);
5395 if (gDoProfileReset) {
5396 if (!initializedJSContext) {
5397 xpc::InitializeJSContext();
5398 initializedJSContext = true;
5401 nsresult backupCreated =
5402 ProfileResetCleanup(mProfileSvc, gResetOldProfile);
5403 if (NS_FAILED(backupCreated)) {
5404 NS_WARNING("Could not cleanup the profile that was reset");
5409 // Initialize user preferences before notifying startup observers so they're
5410 // ready in time for early consumers, such as the component loader.
5411 mDirProvider.InitializeUserPrefs();
5413 // Now that all (user) prefs have been loaded we can initialize the main
5414 // thread's JSContext.
5415 if (!initializedJSContext) {
5416 xpc::InitializeJSContext();
5419 // Finally, now that JS has been initialized, we can finish pref loading.
5420 // This needs to happen after JS and XPConnect initialization because
5421 // AutoConfig files require JS execution. Note that this means AutoConfig
5422 // files can't override JS engine start-up prefs.
5423 mDirProvider.FinishInitializingUserPrefs();
5425 #if defined(MOZ_SANDBOX) && defined(XP_WIN)
5426 // Now that we have preferences and the directory provider, we can
5427 // finish initializing SandboxBroker. This must happen before the GFX
5428 // platform is initialized (which will launch the GPU process), which
5429 // occurs when the "app-startup" category is started up below
5431 // After this completes, we are ready to launch sandboxed processes
5432 mozilla::SandboxBroker::GeckoDependentInitialize();
5433 #endif
5435 nsCOMPtr<nsIFile> workingDir;
5436 rv = NS_GetSpecialDirectory(NS_OS_CURRENT_WORKING_DIR,
5437 getter_AddRefs(workingDir));
5438 if (NS_FAILED(rv)) {
5439 // No working dir? This can happen if it gets deleted before we start.
5440 workingDir = nullptr;
5443 cmdLine = new nsCommandLine();
5445 rv = cmdLine->Init(gArgc, gArgv, workingDir,
5446 nsICommandLine::STATE_INITIAL_LAUNCH);
5447 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
5449 // "app-startup" is the name of both the category and the event
5450 NS_CreateServicesFromCategory("app-startup", cmdLine, "app-startup",
5451 nullptr);
5453 appStartup = components::AppStartup::Service();
5454 NS_ENSURE_TRUE(appStartup, NS_ERROR_FAILURE);
5456 mDirProvider.DoStartup();
5458 #ifdef XP_WIN
5459 // It needs to be called on the main thread because it has to use
5460 // nsObserverService.
5461 EnsureWin32kInitialized();
5462 #endif
5464 // As FilePreferences need the profile directory, we must initialize right
5465 // here.
5466 mozilla::FilePreferences::InitDirectoriesAllowlist();
5467 mozilla::FilePreferences::InitPrefs();
5469 nsCString userAgentLocale;
5470 LocaleService::GetInstance()->GetAppLocaleAsBCP47(userAgentLocale);
5471 CrashReporter::AnnotateCrashReport(
5472 CrashReporter::Annotation::useragent_locale, userAgentLocale);
5474 if (!AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed)) {
5475 /* Special-case services that need early access to the command
5476 line. */
5477 nsCOMPtr<nsIObserverService> obsService =
5478 mozilla::services::GetObserverService();
5479 if (obsService) {
5480 obsService->NotifyObservers(cmdLine, "command-line-startup", nullptr);
5484 #ifdef XP_WIN
5485 // Hack to sync up the various environment storages. XUL_APP_FILE is special
5486 // in that it comes from a different CRT (firefox.exe's static-linked copy).
5487 // Ugly details in http://bugzil.la/1175039#c27
5488 char appFile[MAX_PATH];
5489 if (GetEnvironmentVariableA("XUL_APP_FILE", appFile, sizeof(appFile))) {
5490 SmprintfPointer saved = mozilla::Smprintf("XUL_APP_FILE=%s", appFile);
5491 // We intentionally leak the string here since it is required by
5492 // PR_SetEnv.
5493 PR_SetEnv(saved.release());
5495 #endif
5497 mozilla::AppShutdown::SaveEnvVarsForPotentialRestart();
5499 // clear out any environment variables which may have been set
5500 // during the relaunch process now that we know we won't be relaunching.
5501 SaveToEnv("XRE_PROFILE_PATH=");
5502 SaveToEnv("XRE_PROFILE_LOCAL_PATH=");
5503 SaveToEnv("XRE_START_OFFLINE=");
5504 SaveToEnv("XUL_APP_FILE=");
5505 SaveToEnv("XRE_BINARY_PATH=");
5506 SaveToEnv("XRE_RESTARTED_BY_PROFILE_MANAGER=");
5508 if (!AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed)) {
5509 #ifdef XP_MACOSX
5510 bool lazyHiddenWindow = false;
5511 #else
5512 bool lazyHiddenWindow =
5513 Preferences::GetBool("toolkit.lazyHiddenWindow", false);
5514 #endif
5516 #ifdef MOZ_BACKGROUNDTASKS
5517 if (BackgroundTasks::IsBackgroundTaskMode()) {
5518 // Background tasks aren't going to load a chrome XUL document.
5519 lazyHiddenWindow = true;
5521 #endif
5523 if (!lazyHiddenWindow) {
5524 rv = appStartup->CreateHiddenWindow();
5525 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
5528 #ifdef XP_WIN
5529 Preferences::RegisterCallbackAndCall(
5530 RegisterApplicationRestartChanged,
5531 PREF_WIN_REGISTER_APPLICATION_RESTART);
5532 SetupAlteredPrefetchPref();
5533 SetupSkeletonUIPrefs();
5534 # if defined(MOZ_LAUNCHER_PROCESS)
5535 SetupLauncherProcessPref();
5536 # endif // defined(MOZ_LAUNCHER_PROCESS)
5537 # if defined(MOZ_DEFAULT_BROWSER_AGENT)
5538 # if defined(MOZ_BACKGROUNDTASKS)
5539 // The backgroundtask profile is not a browsing profile, let alone the new
5540 // default profile, so don't mirror its properties into the registry.
5541 if (!BackgroundTasks::IsBackgroundTaskMode())
5542 # endif // defined(MOZ_BACKGROUNDTASKS)
5544 Preferences::RegisterCallbackAndCall(
5545 &OnDefaultAgentTelemetryPrefChanged,
5546 kPrefHealthReportUploadEnabled);
5547 Preferences::RegisterCallbackAndCall(
5548 &OnDefaultAgentTelemetryPrefChanged, kPrefDefaultAgentEnabled);
5550 Preferences::RegisterCallbackAndCall(
5551 &OnDefaultAgentRemoteSettingsPrefChanged,
5552 kPrefServicesSettingsServer);
5553 Preferences::RegisterCallbackAndCall(
5554 &OnDefaultAgentRemoteSettingsPrefChanged,
5555 kPrefSecurityContentSignatureRootHash);
5557 Preferences::RegisterCallbackAndCall(
5558 &OnSetDefaultBrowserUserChoicePrefChanged,
5559 kPrefSetDefaultBrowserUserChoicePref);
5561 SetDefaultAgentLastRunTime();
5563 # endif // defined(MOZ_DEFAULT_BROWSER_AGENT)
5564 #endif
5566 #if defined(MOZ_WIDGET_GTK)
5567 // Clear the environment variables so they won't be inherited by child
5568 // processes and confuse things.
5569 for (const auto& name : kStartupTokenNames) {
5570 g_unsetenv(name.get());
5572 #endif
5574 #ifdef XP_MACOSX
5575 // we re-initialize the command-line service and do appleevents munging
5576 // after we are sure that we're not restarting
5577 cmdLine = new nsCommandLine();
5579 char** tempArgv = static_cast<char**>(malloc(gArgc * sizeof(char*)));
5580 for (int i = 0; i < gArgc; i++) {
5581 tempArgv[i] = strdup(gArgv[i]);
5583 CommandLineServiceMac::SetupMacCommandLine(gArgc, tempArgv, false);
5584 rv = cmdLine->Init(gArgc, tempArgv, workingDir,
5585 nsICommandLine::STATE_INITIAL_LAUNCH);
5586 free(tempArgv);
5587 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
5589 # ifdef MOZILLA_OFFICIAL
5590 // Check if we're running from a DMG or an app translocated location and
5591 // allow the user to install to the Applications directory.
5592 if (MacRunFromDmgUtils::MaybeInstallAndRelaunch()) {
5593 bool userAllowedQuit = true;
5594 appStartup->Quit(nsIAppStartup::eForceQuit, 0, &userAllowedQuit);
5596 # endif
5597 #endif
5599 nsCOMPtr<nsIObserverService> obsService =
5600 mozilla::services::GetObserverService();
5601 if (obsService)
5602 obsService->NotifyObservers(nullptr, "final-ui-startup", nullptr);
5604 (void)appStartup->DoneStartingUp();
5606 CrashReporter::AnnotateCrashReport(
5607 CrashReporter::Annotation::StartupCrash, false);
5609 AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed);
5612 if (!AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed)) {
5613 rv = cmdLine->Run();
5614 NS_ENSURE_SUCCESS_LOG(rv, NS_ERROR_FAILURE);
5617 if (!AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed)) {
5618 #if defined(MOZ_HAS_REMOTE)
5619 // if we have X remote support, start listening for requests on the
5620 // proxy window.
5621 if (mRemoteService && !mDisableRemoteServer) {
5622 mRemoteService->StartupServer();
5623 mRemoteService->UnlockStartup();
5624 gRemoteService = nullptr;
5626 #endif /* MOZ_WIDGET_GTK */
5628 mNativeApp->Enable();
5631 #ifdef MOZ_INSTRUMENT_EVENT_LOOP
5632 if (PR_GetEnv("MOZ_INSTRUMENT_EVENT_LOOP")) {
5633 bool logToConsole = true;
5634 mozilla::InitEventTracing(logToConsole);
5636 #endif /* MOZ_INSTRUMENT_EVENT_LOOP */
5638 // Send Telemetry about Gecko version and buildid
5639 Telemetry::ScalarSet(Telemetry::ScalarID::GECKO_VERSION,
5640 NS_ConvertASCIItoUTF16(gAppData->version));
5641 Telemetry::ScalarSet(Telemetry::ScalarID::GECKO_BUILD_ID,
5642 NS_ConvertASCIItoUTF16(gAppData->buildID));
5644 #if defined(MOZ_SANDBOX) && defined(XP_LINUX)
5645 // If we're on Linux, we now have information about the OS capabilities
5646 // available to us.
5647 SandboxInfo sandboxInfo = SandboxInfo::Get();
5648 Telemetry::Accumulate(Telemetry::SANDBOX_HAS_SECCOMP_BPF,
5649 sandboxInfo.Test(SandboxInfo::kHasSeccompBPF));
5650 Telemetry::Accumulate(Telemetry::SANDBOX_HAS_SECCOMP_TSYNC,
5651 sandboxInfo.Test(SandboxInfo::kHasSeccompTSync));
5652 Telemetry::Accumulate(
5653 Telemetry::SANDBOX_HAS_USER_NAMESPACES_PRIVILEGED,
5654 sandboxInfo.Test(SandboxInfo::kHasPrivilegedUserNamespaces));
5655 Telemetry::Accumulate(Telemetry::SANDBOX_HAS_USER_NAMESPACES,
5656 sandboxInfo.Test(SandboxInfo::kHasUserNamespaces));
5657 Telemetry::Accumulate(Telemetry::SANDBOX_CONTENT_ENABLED,
5658 sandboxInfo.Test(SandboxInfo::kEnabledForContent));
5659 Telemetry::Accumulate(Telemetry::SANDBOX_MEDIA_ENABLED,
5660 sandboxInfo.Test(SandboxInfo::kEnabledForMedia));
5661 nsAutoCString flagsString;
5662 flagsString.AppendInt(sandboxInfo.AsInteger());
5664 CrashReporter::AnnotateCrashReport(
5665 CrashReporter::Annotation::ContentSandboxCapabilities, flagsString);
5666 #endif /* MOZ_SANDBOX && XP_LINUX */
5668 #if defined(XP_WIN)
5669 LauncherResult<bool> isAdminWithoutUac = IsAdminWithoutUac();
5670 if (isAdminWithoutUac.isOk()) {
5671 Telemetry::ScalarSet(
5672 Telemetry::ScalarID::OS_ENVIRONMENT_IS_ADMIN_WITHOUT_UAC,
5673 isAdminWithoutUac.unwrap());
5675 #endif /* XP_WIN */
5677 #if defined(MOZ_SANDBOX)
5678 AddSandboxAnnotations();
5679 #endif /* MOZ_SANDBOX */
5681 mProfileSvc->CompleteStartup();
5684 #ifdef MOZ_BACKGROUNDTASKS
5685 if (BackgroundTasks::IsBackgroundTaskMode()) {
5686 // In background task mode, we don't fire various delayed initialization
5687 // notifications, which in the regular browser is how startup crash tracking
5688 // is marked as finished. Here, getting this far means we don't have a
5689 // startup crash.
5690 rv = appStartup->TrackStartupCrashEnd();
5691 NS_ENSURE_SUCCESS(rv, rv);
5693 // We never open a window, but don't want to exit immediately.
5694 rv = appStartup->EnterLastWindowClosingSurvivalArea();
5695 NS_ENSURE_SUCCESS(rv, rv);
5697 // Avoid some small differences in initialization order across platforms.
5698 nsCOMPtr<nsIPowerManagerService> powerManagerService =
5699 do_GetService(POWERMANAGERSERVICE_CONTRACTID);
5700 nsCOMPtr<nsIStringBundleService> stringBundleService =
5701 do_GetService(NS_STRINGBUNDLE_CONTRACTID);
5703 rv = BackgroundTasks::RunBackgroundTask(cmdLine);
5704 NS_ENSURE_SUCCESS(rv, rv);
5706 #endif
5709 rv = appStartup->Run();
5710 if (NS_FAILED(rv)) {
5711 NS_ERROR("failed to run appstartup");
5712 gLogConsoleErrors = true;
5716 return rv;
5719 #if defined(MOZ_WIDGET_ANDROID)
5720 static already_AddRefed<nsIFile> GreOmniPath(int argc, char** argv) {
5721 nsresult rv;
5723 const char* path = nullptr;
5724 ArgResult ar = CheckArg(argc, argv, "greomni", &path, CheckArgFlag::None);
5725 if (ar == ARG_BAD) {
5726 PR_fprintf(PR_STDERR,
5727 "Error: argument --greomni requires a path argument\n");
5728 return nullptr;
5731 if (!path) return nullptr;
5733 nsCOMPtr<nsIFile> greOmni;
5734 rv = XRE_GetFileFromPath(path, getter_AddRefs(greOmni));
5735 if (NS_FAILED(rv)) {
5736 PR_fprintf(PR_STDERR, "Error: argument --greomni requires a valid path\n");
5737 return nullptr;
5740 return greOmni.forget();
5742 #endif
5745 * XRE_main - A class based main entry point used by most platforms.
5746 * Note that on OSX, aAppData->xreDirectory will point to
5747 * .app/Contents/Resources.
5749 int XREMain::XRE_main(int argc, char* argv[], const BootstrapConfig& aConfig) {
5750 gArgc = argc;
5751 gArgv = argv;
5753 ScopedLogging log;
5755 mozilla::LogModule::Init(gArgc, gArgv);
5757 #ifndef XP_LINUX
5758 NS_SetCurrentThreadName("MainThread");
5759 #endif
5761 AUTO_BASE_PROFILER_LABEL("XREMain::XRE_main (around Gecko Profiler)", OTHER);
5762 AUTO_PROFILER_INIT;
5763 AUTO_PROFILER_LABEL("XREMain::XRE_main", OTHER);
5765 #ifdef XP_MACOSX
5766 // We call this early because it will kick off a background-thread task
5767 // to register the fonts, and we'd like it to have a chance to complete
5768 // before gfxPlatform initialization actually requires it.
5769 gfxPlatformMac::RegisterSupplementalFonts();
5770 #endif
5772 #ifdef MOZ_CODE_COVERAGE
5773 CodeCoverageHandler::Init();
5774 #endif
5776 nsresult rv = NS_OK;
5778 if (aConfig.appData) {
5779 mAppData = MakeUnique<XREAppData>(*aConfig.appData);
5780 } else {
5781 MOZ_RELEASE_ASSERT(aConfig.appDataPath);
5782 nsCOMPtr<nsIFile> appini;
5783 rv = XRE_GetFileFromPath(aConfig.appDataPath, getter_AddRefs(appini));
5784 if (NS_FAILED(rv)) {
5785 Output(true, "Error: unrecognized path: %s\n", aConfig.appDataPath);
5786 return 1;
5789 mAppData = MakeUnique<XREAppData>();
5790 rv = XRE_ParseAppData(appini, *mAppData);
5791 if (NS_FAILED(rv)) {
5792 Output(true, "Couldn't read application.ini");
5793 return 1;
5796 appini->GetParent(getter_AddRefs(mAppData->directory));
5799 if (!mAppData->remotingName) {
5800 mAppData->remotingName = mAppData->name;
5802 // used throughout this file
5803 gAppData = mAppData.get();
5805 nsCOMPtr<nsIFile> binFile;
5806 rv = XRE_GetBinaryPath(getter_AddRefs(binFile));
5807 NS_ENSURE_SUCCESS(rv, 1);
5809 rv = binFile->GetPath(gAbsoluteArgv0Path);
5810 NS_ENSURE_SUCCESS(rv, 1);
5812 if (!mAppData->xreDirectory) {
5813 nsCOMPtr<nsIFile> greDir;
5815 #if defined(MOZ_WIDGET_ANDROID)
5816 greDir = GreOmniPath(argc, argv);
5817 if (!greDir) {
5818 return 2;
5820 #else
5821 rv = binFile->GetParent(getter_AddRefs(greDir));
5822 if (NS_FAILED(rv)) return 2;
5823 #endif
5825 #ifdef XP_MACOSX
5826 nsCOMPtr<nsIFile> parent;
5827 greDir->GetParent(getter_AddRefs(parent));
5828 greDir = parent.forget();
5829 greDir->AppendNative("Resources"_ns);
5830 #endif
5832 mAppData->xreDirectory = greDir;
5835 #if defined(MOZ_WIDGET_ANDROID)
5836 nsCOMPtr<nsIFile> dataDir;
5837 rv = binFile->GetParent(getter_AddRefs(dataDir));
5838 if (NS_FAILED(rv)) return 2;
5840 mAppData->directory = dataDir;
5841 #else
5842 if (aConfig.appData && aConfig.appDataPath) {
5843 mAppData->xreDirectory->Clone(getter_AddRefs(mAppData->directory));
5844 mAppData->directory->AppendNative(nsDependentCString(aConfig.appDataPath));
5846 #endif
5848 if (!mAppData->directory) {
5849 mAppData->directory = mAppData->xreDirectory;
5852 #if defined(XP_WIN)
5853 # if defined(MOZ_SANDBOX)
5854 mAppData->sandboxBrokerServices = aConfig.sandboxBrokerServices;
5855 # endif // defined(MOZ_SANDBOX)
5858 DebugOnly<bool> result = WindowsBCryptInitialization();
5859 MOZ_ASSERT(result);
5862 # if defined(_M_IX86) || defined(_M_X64)
5864 DebugOnly<bool> result = WindowsMsctfInitialization();
5865 MOZ_ASSERT(result);
5867 # endif // _M_IX86 || _M_X64
5869 #endif // defined(XP_WIN)
5871 // Once we unset the exception handler, we lose the ability to properly
5872 // detect hangs -- they show up as crashes. We do this as late as possible.
5873 // In particular, after ProcessRuntime is destroyed on Windows.
5874 auto unsetExceptionHandler = MakeScopeExit([&] {
5875 if (mAppData->flags & NS_XRE_ENABLE_CRASH_REPORTER)
5876 return CrashReporter::UnsetExceptionHandler();
5877 return NS_OK;
5880 mozilla::AutoIOInterposer ioInterposerGuard;
5881 ioInterposerGuard.Init();
5883 #if defined(XP_WIN)
5884 // We should have already done this when we created the skeleton UI. However,
5885 // there is code in here which needs xul in order to work, like EnsureMTA. It
5886 // should be setup that running it again is safe.
5887 mozilla::mscom::ProcessRuntime msCOMRuntime;
5888 #endif
5890 // init
5891 bool exit = false;
5892 int result = XRE_mainInit(&exit);
5893 if (result != 0 || exit) return result;
5895 // If we exit gracefully, remove the startup crash canary file.
5896 auto cleanup = MakeScopeExit([&]() -> nsresult {
5897 if (mProfLD) {
5898 nsCOMPtr<nsIFile> crashFile;
5899 MOZ_TRY_VAR(crashFile, GetIncompleteStartupFile(mProfLD));
5900 crashFile->Remove(false);
5902 return NS_OK;
5905 // startup
5906 result = XRE_mainStartup(&exit);
5907 if (result != 0 || exit) return result;
5909 // Start the real application. We use |aInitJSContext = false| because
5910 // XRE_mainRun wants to initialize the JSContext after reading user prefs.
5912 mScopedXPCOM = MakeUnique<ScopedXPCOMStartup>();
5914 rv = mScopedXPCOM->Initialize(/* aInitJSContext = */ false);
5915 NS_ENSURE_SUCCESS(rv, 1);
5917 // run!
5918 rv = XRE_mainRun();
5920 #ifdef MOZ_X11
5921 XRE_CleanupX11ErrorHandler();
5922 #endif
5924 #ifdef MOZ_INSTRUMENT_EVENT_LOOP
5925 mozilla::ShutdownEventTracing();
5926 #endif
5928 gAbsoluteArgv0Path.Truncate();
5930 #if defined(MOZ_HAS_REMOTE)
5931 // Shut down the remote service. We must do this before calling LaunchChild
5932 // if we're restarting because otherwise the new instance will attempt to
5933 // remote to this instance.
5934 if (mRemoteService && !mDisableRemoteServer) {
5935 mRemoteService->ShutdownServer();
5937 #endif /* MOZ_WIDGET_GTK */
5939 mScopedXPCOM = nullptr;
5941 // unlock the profile after ScopedXPCOMStartup object (xpcom)
5942 // has gone out of scope. see bug #386739 for more details
5943 mProfileLock->Unlock();
5944 gProfileLock = nullptr;
5946 gLastAppVersion.Truncate();
5947 gLastAppBuildID.Truncate();
5949 mozilla::AppShutdown::MaybeDoRestart();
5951 #ifdef MOZ_WIDGET_GTK
5952 // gdk_display_close also calls gdk_display_manager_set_default_display
5953 // appropriately when necessary.
5954 if (!gfxPlatform::IsHeadless()) {
5955 # ifdef MOZ_WAYLAND
5956 WaylandDisplayRelease();
5957 # endif
5959 #endif
5961 XRE_DeinitCommandLine();
5963 if (NS_FAILED(rv)) {
5964 return 1;
5966 return mozilla::AppShutdown::GetExitCode();
5969 void XRE_StopLateWriteChecks(void) { mozilla::StopLateWriteChecks(); }
5971 int XRE_main(int argc, char* argv[], const BootstrapConfig& aConfig) {
5972 XREMain main;
5974 int result = main.XRE_main(argc, argv, aConfig);
5975 mozilla::RecordShutdownEndTimeStamp();
5976 #ifdef MOZ_BACKGROUNDTASKS
5977 // This is well after the profile has been unlocked, so it's okay if this does
5978 // delete this background task's temporary profile.
5979 mozilla::BackgroundTasks::Shutdown();
5980 #endif
5981 return result;
5984 nsresult XRE_InitCommandLine(int aArgc, char* aArgv[]) {
5985 nsresult rv = NS_OK;
5987 #if defined(XP_WIN)
5988 CommandLine::Init(aArgc, aArgv);
5989 #else
5991 // these leak on error, but that's OK: we'll just exit()
5992 char** canonArgs = new char*[aArgc];
5994 // get the canonical version of the binary's path
5995 nsCOMPtr<nsIFile> binFile;
5996 rv = XRE_GetBinaryPath(getter_AddRefs(binFile));
5997 if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
5999 nsAutoCString canonBinPath;
6000 rv = binFile->GetNativePath(canonBinPath);
6001 if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
6003 canonArgs[0] = strdup(canonBinPath.get());
6005 for (int i = 1; i < aArgc; ++i) {
6006 if (aArgv[i]) {
6007 canonArgs[i] = strdup(aArgv[i]);
6011 NS_ASSERTION(!CommandLine::IsInitialized(), "Bad news!");
6012 CommandLine::Init(aArgc, canonArgs);
6014 for (int i = 0; i < aArgc; ++i) free(canonArgs[i]);
6015 delete[] canonArgs;
6016 #endif
6018 #if defined(MOZ_WIDGET_ANDROID)
6019 // gAppData is non-null iff this is the parent process. Otherwise,
6020 // the `-greomni`/`-appomni` flags are cross-platform and handled in
6021 // ContentProcess::Init.
6022 if (gAppData) {
6023 nsCOMPtr<nsIFile> greOmni = gAppData->xreDirectory;
6024 if (!greOmni) {
6025 return NS_ERROR_FAILURE;
6027 mozilla::Omnijar::Init(greOmni, greOmni);
6029 #endif
6031 return rv;
6034 nsresult XRE_DeinitCommandLine() {
6035 nsresult rv = NS_OK;
6037 CommandLine::Terminate();
6039 return rv;
6042 GeckoProcessType XRE_GetProcessType() { return GetGeckoProcessType(); }
6044 const char* XRE_GetProcessTypeString() {
6045 return XRE_GeckoProcessTypeToString(XRE_GetProcessType());
6048 bool XRE_IsE10sParentProcess() {
6049 #ifdef MOZ_WIDGET_ANDROID
6050 return XRE_IsParentProcess() && BrowserTabsRemoteAutostart() &&
6051 mozilla::jni::IsAvailable();
6052 #else
6053 return XRE_IsParentProcess() && BrowserTabsRemoteAutostart();
6054 #endif
6057 #define GECKO_PROCESS_TYPE(enum_value, enum_name, string_name, proc_typename, \
6058 process_bin_type, procinfo_typename, \
6059 webidl_typename, allcaps_name) \
6060 bool XRE_Is##proc_typename##Process() { \
6061 return XRE_GetProcessType() == GeckoProcessType_##enum_name; \
6063 #include "mozilla/GeckoProcessTypes.h"
6064 #undef GECKO_PROCESS_TYPE
6066 bool XRE_UseNativeEventProcessing() {
6067 switch (XRE_GetProcessType()) {
6068 #if defined(XP_MACOSX) || defined(XP_WIN)
6069 case GeckoProcessType_RDD:
6070 case GeckoProcessType_Socket:
6071 return false;
6072 case GeckoProcessType_Utility: {
6073 # if defined(XP_WIN)
6074 auto upc = mozilla::ipc::UtilityProcessChild::Get();
6075 MOZ_ASSERT(upc);
6077 using SboxKind = mozilla::ipc::SandboxingKind;
6078 // These processes are used as external hosts for accessing Windows
6079 // APIs which (may) require a Windows native event loop.
6080 return upc->mSandbox == SboxKind::WINDOWS_UTILS ||
6081 upc->mSandbox == SboxKind::WINDOWS_FILE_DIALOG;
6082 # else
6083 return false;
6084 # endif // defined(XP_WIN)
6086 #endif // defined(XP_MACOSX) || defined(XP_WIN)
6087 case GeckoProcessType_GMPlugin:
6088 return mozilla::gmp::GMPProcessChild::UseNativeEventProcessing();
6089 case GeckoProcessType_Content:
6090 return StaticPrefs::dom_ipc_useNativeEventProcessing_content();
6091 default:
6092 return true;
6096 namespace mozilla {
6098 uint32_t GetMaxWebProcessCount() {
6099 // multiOptOut is in int to allow us to run multiple experiments without
6100 // introducing multiple prefs a la the autostart.N prefs.
6101 if (Preferences::GetInt("dom.ipc.multiOptOut", 0) >=
6102 nsIXULRuntime::E10S_MULTI_EXPERIMENT) {
6103 return 1;
6106 const char* optInPref = "dom.ipc.processCount";
6107 uint32_t optInPrefValue = Preferences::GetInt(optInPref, 1);
6108 return std::max(1u, optInPrefValue);
6111 const char* PlatformBuildID() { return gToolkitBuildID; }
6113 } // namespace mozilla
6115 void SetupErrorHandling(const char* progname) {
6116 #ifdef XP_WIN
6117 /* On Windows XPSP3 and Windows Vista if DEP is configured off-by-default
6118 we still want DEP protection: enable it explicitly and programmatically.
6120 This function is not available on WinXPSP2 so we dynamically load it.
6123 HMODULE kernel32 = GetModuleHandleW(L"kernel32.dll");
6124 SetProcessDEPPolicyFunc _SetProcessDEPPolicy =
6125 (SetProcessDEPPolicyFunc)GetProcAddress(kernel32, "SetProcessDEPPolicy");
6126 if (_SetProcessDEPPolicy) _SetProcessDEPPolicy(PROCESS_DEP_ENABLE);
6127 #endif
6129 #ifdef XP_WIN
6130 // Suppress the "DLL Foo could not be found" dialog, such that if dependent
6131 // libraries (such as GDI+) are not preset, we gracefully fail to load those
6132 // XPCOM components, instead of being ungraceful.
6133 UINT realMode = SetErrorMode(0);
6134 realMode |= SEM_FAILCRITICALERRORS;
6135 // If XRE_NO_WINDOWS_CRASH_DIALOG is set, suppress displaying the "This
6136 // application has crashed" dialog box. This is mainly useful for
6137 // automated testing environments, e.g. tinderbox, where there's no need
6138 // for a dozen of the dialog boxes to litter the console
6139 if (getenv("XRE_NO_WINDOWS_CRASH_DIALOG"))
6140 realMode |= SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX;
6142 SetErrorMode(realMode);
6144 #endif
6146 InstallSignalHandlers(progname);
6148 // Unbuffer stdout, needed for tinderbox tests.
6149 setbuf(stdout, 0);
6152 static bool gRunSelfAsContentProc = false;
6154 void XRE_EnableSameExecutableForContentProc() {
6155 if (!PR_GetEnv("MOZ_SEPARATE_CHILD_PROCESS")) {
6156 gRunSelfAsContentProc = true;
6160 mozilla::BinPathType XRE_GetChildProcBinPathType(
6161 GeckoProcessType aProcessType) {
6162 MOZ_ASSERT(aProcessType != GeckoProcessType_Default);
6164 if (!gRunSelfAsContentProc) {
6165 return BinPathType::PluginContainer;
6168 #ifdef XP_WIN
6169 // On Windows, plugin-container may or may not be used depending on
6170 // the process type (e.g., actual plugins vs. content processes)
6171 switch (aProcessType) {
6172 # define GECKO_PROCESS_TYPE(enum_value, enum_name, string_name, \
6173 proc_typename, process_bin_type, \
6174 procinfo_typename, webidl_typename, allcaps_name) \
6175 case GeckoProcessType_##enum_name: \
6176 return BinPathType::process_bin_type;
6177 # include "mozilla/GeckoProcessTypes.h"
6178 # undef GECKO_PROCESS_TYPE
6179 default:
6180 return BinPathType::PluginContainer;
6182 #else
6183 // On (non-macOS) Unix, plugin-container isn't used (except in cases
6184 // like xpcshell that are handled by the gRunSelfAsContentProc check
6185 // above). It isn't necessary the way it is on other platforms, and
6186 // it interferes with using the fork server.
6187 return BinPathType::Self;
6188 #endif
6191 // From mozglue/static/rust/lib.rs
6192 extern "C" void install_rust_hooks();
6194 struct InstallRustHooks {
6195 InstallRustHooks() { install_rust_hooks(); }
6198 InstallRustHooks sInstallRustHooks;
6200 #ifdef MOZ_ASAN_REPORTER
6201 void setASanReporterPath(nsIFile* aDir) {
6202 nsCOMPtr<nsIFile> dir;
6203 aDir->Clone(getter_AddRefs(dir));
6205 dir->Append(u"asan"_ns);
6206 nsresult rv = dir->Create(nsIFile::DIRECTORY_TYPE, 0700);
6207 if (NS_WARN_IF(NS_FAILED(rv) && rv != NS_ERROR_FILE_ALREADY_EXISTS)) {
6208 MOZ_CRASH("[ASan Reporter] Unable to create crash directory.");
6211 dir->Append(u"ff_asan_log"_ns);
6213 # ifdef XP_WIN
6214 nsAutoString nspathW;
6215 rv = dir->GetPath(nspathW);
6216 NS_ConvertUTF16toUTF8 nspath(nspathW);
6217 # else
6218 nsAutoCString nspath;
6219 rv = dir->GetNativePath(nspath);
6220 # endif
6221 if (NS_FAILED(rv)) {
6222 MOZ_CRASH("[ASan Reporter] Unable to get native path for crash directory.");
6225 __sanitizer_set_report_path(nspath.get());
6227 #endif