1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "mozilla/dom/ContentParent.h"
7 #include "mozilla/dom/ContentChild.h"
8 #include "mozilla/ipc/GeckoChildProcessHost.h"
10 #include "mozilla/AppShutdown.h"
11 #include "mozilla/ArrayUtils.h"
12 #include "mozilla/Assertions.h"
13 #include "mozilla/Attributes.h"
14 #include "mozilla/Components.h"
15 #include "mozilla/FilePreferences.h"
16 #include "mozilla/ChaosMode.h"
17 #include "mozilla/CmdLineAndEnvUtils.h"
18 #include "mozilla/IOInterposer.h"
19 #include "mozilla/ipc/UtilityProcessChild.h"
20 #include "mozilla/Likely.h"
21 #include "mozilla/MemoryChecking.h"
22 #include "mozilla/Poison.h"
23 #include "mozilla/Preferences.h"
24 #include "mozilla/PreferenceSheet.h"
25 #include "mozilla/Printf.h"
26 #include "mozilla/ProcessType.h"
27 #include "mozilla/ResultExtensions.h"
28 #include "mozilla/RuntimeExceptionModule.h"
29 #include "mozilla/ScopeExit.h"
30 #include "mozilla/StaticPrefs_browser.h"
31 #include "mozilla/StaticPrefs_fission.h"
32 #include "mozilla/StaticPrefs_webgl.h"
33 #include "mozilla/StaticPrefs_widget.h"
34 #include "mozilla/Telemetry.h"
35 #include "mozilla/Utf8.h"
36 #include "mozilla/intl/LocaleService.h"
37 #include "mozilla/JSONWriter.h"
38 #include "mozilla/gfx/gfxVars.h"
39 #include "mozilla/glean/GleanMetrics.h"
40 #include "mozilla/glean/GleanPings.h"
41 #include "mozilla/widget/TextRecognition.h"
42 #include "BaseProfiler.h"
43 #include "mozJSModuleLoader.h"
45 #include "nsAppRunner.h"
46 #include "mozilla/XREAppData.h"
47 #include "mozilla/Bootstrap.h"
48 #if defined(MOZ_UPDATER) && !defined(MOZ_WIDGET_ANDROID)
49 # include "nsUpdateDriver.h"
50 # include "nsUpdateSyncManager.h"
52 #include "ProfileReset.h"
54 #ifdef MOZ_INSTRUMENT_EVENT_LOOP
55 # include "EventTracer.h"
59 # include "nsVersionComparator.h"
60 # include "MacLaunchHelper.h"
61 # include "MacApplicationDelegate.h"
62 # include "MacAutoreleasePool.h"
63 # include "MacRunFromDmgUtils.h"
64 // these are needed for sysctl
65 # include <sys/types.h>
66 # include <sys/sysctl.h>
75 #include "nsIAppStartup.h"
76 #include "nsCategoryManagerUtils.h"
77 #include "nsIMutableArray.h"
78 #include "nsCommandLine.h"
79 #include "nsIComponentRegistrar.h"
80 #include "nsIDialogParamBlock.h"
81 #include "mozilla/ModuleUtils.h"
82 #include "nsIIOService.h"
83 #include "nsIObserverService.h"
84 #include "nsINativeAppSupport.h"
85 #include "nsIPlatformInfo.h"
86 #include "nsIProcess.h"
87 #include "nsIProfileUnlocker.h"
88 #include "nsIPromptService.h"
89 #include "nsIPropertyBag2.h"
90 #include "nsIServiceManager.h"
91 #include "nsIStringBundle.h"
92 #include "nsISupportsPrimitives.h"
93 #include "nsIToolkitProfile.h"
94 #include "nsToolkitProfileService.h"
97 #include "nsIWindowCreator.h"
98 #include "nsIWindowWatcher.h"
99 #include "nsIXULAppInfo.h"
100 #include "nsIXULRuntime.h"
101 #include "nsPIDOMWindow.h"
102 #include "nsIWidget.h"
103 #include "nsAppShellCID.h"
104 #include "mozilla/dom/quota/QuotaManager.h"
105 #include "mozilla/scache/StartupCache.h"
106 #include "gfxPlatform.h"
107 #include "PDMFactory.h"
109 # include "gfxPlatformMac.h"
112 #include "mozilla/Unused.h"
115 # include "nsIWinAppHelper.h"
116 # include <windows.h>
119 # include "cairo/cairo-features.h"
120 # include "detect_win32k_conflicts.h"
121 # include "mozilla/PreXULSkeletonUI.h"
122 # include "mozilla/DllPrefetchExperimentRegistryInfo.h"
123 # include "mozilla/WindowsBCryptInitialization.h"
124 # include "mozilla/WindowsDllBlocklist.h"
125 # include "mozilla/WindowsMsctfInitialization.h"
126 # include "mozilla/WindowsProcessMitigations.h"
127 # include "mozilla/WindowsVersion.h"
128 # include "mozilla/WinHeaderOnlyUtils.h"
129 # include "mozilla/mscom/ProcessRuntime.h"
130 # include "mozilla/mscom/ProfilerMarkers.h"
131 # include "WinTokenUtils.h"
133 # if defined(MOZ_LAUNCHER_PROCESS)
134 # include "mozilla/LauncherRegistryInfo.h"
137 # if defined(MOZ_DEFAULT_BROWSER_AGENT)
138 # include "nsIWindowsRegKey.h"
141 # ifndef PROCESS_DEP_ENABLE
142 # define PROCESS_DEP_ENABLE 0x1
146 #if defined(MOZ_SANDBOX)
147 # include "mozilla/SandboxSettings.h"
151 # include "nsAccessibilityService.h"
153 # include "mozilla/a11y/Compatibility.h"
154 # include "mozilla/a11y/Platform.h"
159 #include "nsCOMPtr.h"
160 #include "nsDirectoryServiceDefs.h"
161 #include "nsDirectoryServiceUtils.h"
162 #include "nsEmbedCID.h"
163 #include "nsIDUtils.h"
164 #include "nsNetUtil.h"
165 #include "nsReadableUtils.h"
167 #include "nsXPCOMCIDInternal.h"
168 #include "nsString.h"
169 #include "nsPrintfCString.h"
170 #include "nsVersionComparator.h"
172 #include "nsAppDirectoryServiceDefs.h"
173 #include "nsXULAppAPI.h"
174 #include "nsXREDirProvider.h"
176 #include "nsINIParser.h"
177 #include "mozilla/Omnijar.h"
178 #include "mozilla/StartupTimeline.h"
179 #include "mozilla/LateWriteChecks.h"
188 # include <sys/resource.h>
189 # include <sys/stat.h>
194 # include <process.h>
196 # include "mozilla/WinDllServices.h"
197 # include "nsThreadUtils.h"
198 # include "WinUtils.h"
202 # include "nsILocalFileMac.h"
203 # include "nsCommandLineServiceMac.h"
206 // for X remote support
207 #if defined(MOZ_HAS_REMOTE)
208 # include "nsRemoteService.h"
211 #if defined(DEBUG) && defined(XP_WIN)
215 #if defined(XP_MACOSX)
216 # include <Carbon/Carbon.h>
220 # include "mozilla/Logging.h"
227 #include "nsExceptionHandler.h"
228 #include "nsICrashReporter.h"
229 #include "nsIPrefService.h"
230 #include "nsIMemoryInfoDumper.h"
231 #if defined(XP_LINUX) && !defined(ANDROID)
232 # include "mozilla/widget/LSBUtils.h"
235 #include "base/command_line.h"
236 #include "GTestRunner.h"
238 #ifdef MOZ_WIDGET_ANDROID
239 # include "mozilla/java/GeckoAppShellWrappers.h"
242 #if defined(MOZ_SANDBOX)
243 # if defined(XP_LINUX) && !defined(ANDROID)
244 # include "mozilla/SandboxInfo.h"
245 # elif defined(XP_WIN)
246 # include "sandboxBroker.h"
250 #ifdef MOZ_CODE_COVERAGE
251 # include "mozilla/CodeCoverageHandler.h"
254 #include "GMPProcessChild.h"
255 #include "SafeMode.h"
257 #ifdef MOZ_BACKGROUNDTASKS
258 # include "mozilla/BackgroundTasks.h"
259 # include "nsIPowerManagerService.h"
260 # include "nsIStringBundle.h"
264 # include "mozilla/GUniquePtr.h"
265 # include "mozilla/GfxInfo.h"
268 #ifdef MOZ_WIDGET_GTK
269 # include "nsAppShell.h"
271 #ifdef MOZ_ENABLE_DBUS
272 # include "DBusService.h"
275 extern uint32_t gRestartMode
;
276 extern void InstallSignalHandlers(const char* ProgramName
);
278 #define FILE_COMPATIBILITY_INFO "compatibility.ini"_ns
279 #define FILE_INVALIDATE_CACHES ".purgecaches"_ns
280 #define FILE_STARTUP_INCOMPLETE u".startup-incomplete"_ns
282 #if defined(MOZ_BLOCK_PROFILE_DOWNGRADE) || defined(MOZ_LAUNCHER_PROCESS) || \
283 defined(MOZ_DEFAULT_BROWSER_AGENT)
284 static const char kPrefHealthReportUploadEnabled
[] =
285 "datareporting.healthreport.uploadEnabled";
286 #endif // defined(MOZ_BLOCK_PROFILE_DOWNGRADE) || defined(MOZ_LAUNCHER_PROCESS)
287 // || defined(MOZ_DEFAULT_BROWSER_AGENT)
288 #if defined(MOZ_DEFAULT_BROWSER_AGENT)
289 static const char kPrefDefaultAgentEnabled
[] = "default-browser-agent.enabled";
291 static const char kPrefServicesSettingsServer
[] = "services.settings.server";
292 static const char kPrefSetDefaultBrowserUserChoicePref
[] =
293 "browser.shell.setDefaultBrowserUserChoice";
294 #endif // defined(MOZ_DEFAULT_BROWSER_AGENT)
297 static const char kPrefThemeId
[] = "extensions.activeThemeID";
298 static const char kPrefBrowserStartupBlankWindow
[] =
299 "browser.startup.blankWindow";
300 static const char kPrefPreXulSkeletonUI
[] = "browser.startup.preXulSkeletonUI";
301 #endif // defined(XP_WIN)
303 #if defined(MOZ_WIDGET_GTK)
304 constexpr nsLiteralCString kStartupTokenNames
[] = {
305 "XDG_ACTIVATION_TOKEN"_ns
,
306 "DESKTOP_STARTUP_ID"_ns
,
313 static const char gToolkitVersion
[] = MOZ_STRINGIFY(GRE_MILESTONE
);
314 // The gToolkitBuildID global is defined to MOZ_BUILDID via gen_buildid.py
315 // in toolkit/library. See related comment in toolkit/library/moz.build.
316 extern const char gToolkitBuildID
[];
318 static nsIProfileLock
* gProfileLock
;
319 #if defined(MOZ_HAS_REMOTE)
320 static RefPtr
<nsRemoteService
> gRemoteService
;
326 // If gRestartedByOS is set, we were automatically restarted by the OS.
327 bool gRestartedByOS
= false;
329 bool gIsGtest
= false;
331 bool gKioskMode
= false;
332 int gKioskMonitor
= -1;
334 bool gAllowContentAnalysisArgPresent
= false;
336 nsString gAbsoluteArgv0Path
;
339 nsString gProcessStartupShortcut
;
342 #if defined(MOZ_WIDGET_GTK)
344 # include "mozilla/WidgetUtilsGtk.h"
345 # include <gtk/gtk.h>
347 # include <gdk/gdkwayland.h>
348 # include "mozilla/widget/nsWaylandDisplay.h"
349 # include "wayland-proxy.h"
352 # include <gdk/gdkx.h>
353 # endif /* MOZ_X11 */
356 #if defined(MOZ_WAYLAND)
357 std::unique_ptr
<WaylandProxy
> gWaylandProxy
;
360 #include "BinaryPath.h"
363 # include "mozilla/Logging.h"
364 extern mozilla::LazyLogModule gWidgetWaylandLog
;
365 #endif /* MOZ_LOGGING */
368 # include "FuzzerRunner.h"
371 FuzzerRunner
* fuzzerRunner
= 0;
372 } // namespace mozilla
375 void XRE_LibFuzzerSetDriver(LibFuzzerDriver aDriver
) {
376 mozilla::fuzzerRunner
->setParams(aDriver
);
381 // Undo X11/X.h's definition of None
385 int (*RunGTest
)(int*, char**) = 0;
387 bool RunningGTest() { return RunGTest
; }
388 } // namespace mozilla
390 using namespace mozilla
;
391 using namespace mozilla::widget
;
392 using namespace mozilla::startup
;
393 using mozilla::Unused
;
394 using mozilla::dom::ContentChild
;
395 using mozilla::dom::ContentParent
;
396 using mozilla::dom::quota::QuotaManager
;
397 using mozilla::intl::LocaleService
;
398 using mozilla::scache::StartupCache
;
400 // Save the given word to the specified environment variable.
401 static void MOZ_NEVER_INLINE
SaveWordToEnv(const char* name
,
402 const nsACString
& word
) {
404 Smprintf("%s=%s", name
, PromiseFlatCString(word
).get()).release();
405 if (expr
) PR_SetEnv(expr
);
406 // We intentionally leak |expr| here since it is required by PR_SetEnv.
409 // Save the path of the given file to the specified environment variable.
410 static void SaveFileToEnv(const char* name
, nsIFile
* file
) {
414 SetEnvironmentVariableW(NS_ConvertASCIItoUTF16(name
).get(), path
.get());
417 file
->GetNativePath(path
);
418 SaveWordToEnv(name
, path
);
422 static bool gIsExpectedExit
= false;
424 void MozExpectedExit() { gIsExpectedExit
= true; }
427 * Runs atexit() to catch unexpected exit from 3rd party libraries like the
428 * Intel graphics driver calling exit in an error condition. When they
429 * call exit() to report an error we won't shutdown correctly and wont catch
430 * the issue with our crash reporter.
432 static void UnexpectedExit() {
433 if (!gIsExpectedExit
) {
434 gIsExpectedExit
= true; // Don't risk re-entrency issues when crashing.
435 MOZ_CRASH("Exit called by third party code.");
439 #if defined(MOZ_WAYLAND)
440 bool IsWaylandEnabled() {
441 static bool isWaylandEnabled
= []() {
442 const char* waylandDisplay
= PR_GetEnv("WAYLAND_DISPLAY");
443 if (!waylandDisplay
) {
446 if (!PR_GetEnv("DISPLAY")) {
447 // No X11 display, so try to run wayland.
450 // MOZ_ENABLE_WAYLAND is our primary Wayland on/off switch.
451 if (const char* waylandPref
= PR_GetEnv("MOZ_ENABLE_WAYLAND")) {
452 return *waylandPref
== '1';
454 if (const char* backendPref
= PR_GetEnv("GDK_BACKEND")) {
455 if (!strncmp(backendPref
, "wayland", 7)) {
457 "Wayland backend should be enabled by MOZ_ENABLE_WAYLAND=1."
458 "GDK_BACKEND is a Gtk3 debug variable and may cause issues.");
462 // Enable by default when we're running on a recent enough GTK version. We'd
463 // like to check further details like compositor version and so on ideally
464 // to make sure we don't enable it on old Mutter or what not, but we can't,
465 // so let's assume that if the user is running on a Wayland session by
466 // default we're ok, since either the distro has enabled Wayland by default,
467 // or the user has gone out of their way to use Wayland.
468 return !gtk_check_version(3, 24, 30);
470 return isWaylandEnabled
;
473 bool IsWaylandEnabled() { return false; }
477 * Output a string to the user. This method is really only meant to be used to
478 * output last-ditch error messages designed for developers NOT END USERS.
481 * Pass true to indicate severe errors.
483 * printf-style format string followed by arguments.
485 static MOZ_FORMAT_PRINTF(2, 3) void Output(bool isError
, const char* fmt
, ...) {
489 #if defined(XP_WIN) && !MOZ_WINCONSOLE
490 SmprintfPointer msg
= mozilla::Vsmprintf(fmt
, ap
);
494 flags
|= MB_ICONERROR
;
496 flags
|= MB_ICONINFORMATION
;
498 wchar_t wide_msg
[1024];
499 MultiByteToWideChar(CP_ACP
, 0, msg
.get(), -1, wide_msg
,
500 sizeof(wide_msg
) / sizeof(wchar_t));
502 wchar_t wide_caption
[128];
503 MultiByteToWideChar(CP_ACP
, 0, gAppData
? gAppData
->name
: "XULRunner", -1,
504 wide_caption
, sizeof(wide_caption
) / sizeof(wchar_t));
505 MessageBoxW(nullptr, wide_msg
, wide_caption
, flags
);
507 #elif defined(MOZ_WIDGET_ANDROID)
508 SmprintfPointer msg
= mozilla::Vsmprintf(fmt
, ap
);
510 __android_log_print(isError
? ANDROID_LOG_ERROR
: ANDROID_LOG_INFO
,
511 "GeckoRuntime", "%s", msg
.get());
514 vfprintf(stderr
, fmt
, ap
);
521 * Check for a commandline flag. If the flag takes a parameter, the
522 * parameter is returned in aParam. Flags may be in the form -arg or
523 * --arg (or /arg on win32).
525 * @param aArg the parameter to check. Must be lowercase.
526 * @param aParam if non-null, the -arg <data> will be stored in this pointer.
527 * This is *not* allocated, but rather a pointer to the argv data.
528 * @param aFlags flags @see CheckArgFlag
530 static ArgResult
CheckArg(const char* aArg
, const char** aParam
= nullptr,
531 CheckArgFlag aFlags
= CheckArgFlag::RemoveArg
) {
532 MOZ_ASSERT(gArgv
, "gArgv must be initialized before CheckArg()");
533 return CheckArg(gArgc
, gArgv
, aArg
, aParam
, aFlags
);
537 * Check for a commandline flag. Ignore data that's passed in with the flag.
538 * Flags may be in the form -arg or --arg (or /arg on win32).
539 * Will not remove flag if found.
541 * @param aArg the parameter to check. Must be lowercase.
543 static ArgResult
CheckArgExists(const char* aArg
) {
544 return CheckArg(aArg
, nullptr, CheckArgFlag::None
);
547 bool gSafeMode
= false;
548 bool gFxREmbedded
= false;
551 kE10sEnabledByDefault
,
555 static bool gBrowserTabsRemoteAutostart
= false;
556 static E10sStatus gBrowserTabsRemoteStatus
;
557 static bool gBrowserTabsRemoteAutostartInitialized
= false;
561 bool BrowserTabsRemoteAutostart() {
562 if (gBrowserTabsRemoteAutostartInitialized
) {
563 return gBrowserTabsRemoteAutostart
;
565 gBrowserTabsRemoteAutostartInitialized
= true;
567 // If we're not in the parent process, we are running E10s.
568 if (!XRE_IsParentProcess()) {
569 gBrowserTabsRemoteAutostart
= true;
570 return gBrowserTabsRemoteAutostart
;
573 gBrowserTabsRemoteAutostart
= true;
574 E10sStatus status
= kE10sEnabledByDefault
;
576 // We are checking to ensure that either MOZILLA_OFFICIAL is undefined or that
577 // xpc::AreNonLocalConnectionsDisabled() is true. If either check matches,
578 // we move on to check the MOZ_FORCE_DISABLE_E10S environment variable which
579 // must equal "1" to proceed with disabling e10s.
580 #if defined(MOZILLA_OFFICIAL)
581 bool allowDisablingE10s
= xpc::AreNonLocalConnectionsDisabled();
583 bool allowDisablingE10s
= true;
586 if (gBrowserTabsRemoteAutostart
&& allowDisablingE10s
) {
587 const char* forceDisable
= PR_GetEnv("MOZ_FORCE_DISABLE_E10S");
588 if (forceDisable
&& !strcmp(forceDisable
, "1")) {
589 gBrowserTabsRemoteAutostart
= false;
590 status
= kE10sForceDisabled
;
594 gBrowserTabsRemoteStatus
= status
;
596 return gBrowserTabsRemoteAutostart
;
599 } // namespace mozilla
601 // Win32k Infrastructure ==============================================
603 // This bool tells us if we have initialized the following two statics
606 static bool gWin32kInitialized
= false;
608 // Win32k Lockdown for the current session is determined once, at startup,
609 // and then remains the same for the duration of the session.
611 static nsIXULRuntime::ContentWin32kLockdownState gWin32kStatus
;
613 // The status of the win32k experiment. It is determined once, at startup,
614 // and then remains the same for the duration of the session.
616 static nsIXULRuntime::ExperimentStatus gWin32kExperimentStatus
=
617 nsIXULRuntime::eExperimentStatusUnenrolled
;
620 // The states for win32k lockdown can be generalized to:
621 // - User doesn't meet requirements (bad OS, webrender, remotegl) aka
622 // PersistentRequirement
623 // - User has Safe Mode enabled, Win32k Disabled by Env Var, or E10S disabled
624 // by Env Var aka TemporaryRequirement
625 // - User has set the win32k pref to something non-default aka NonDefaultPref
626 // - User has been enrolled in the experiment and does what it says aka
628 // - User does the default aka Default
630 // We expect the below behvaior. In the code, there may be references to these
631 // behaviors (e.g. [A]) but not always.
633 // [A] Becoming enrolled in the experiment while NonDefaultPref disqualifies
634 // you upon next browser start
635 // [B] Becoming enrolled in the experiment while PersistentRequirement
636 // disqualifies you upon next browser start
637 // [C] Becoming enrolled in the experiment while TemporaryRequirement does not
639 // [D] Becoming enrolled in the experiment will only take effect after restart
640 // [E] While enrolled, becoming PersistentRequirement will not disqualify you
641 // until browser restart, but if the state is present at browser start,
642 // will disqualify you. Additionally, it will not affect the session value
644 // XXX(bobowen): I hope both webrender and wbgl.out-of-process require a
645 // restart to take effect!
646 // [F] While enrolled, becoming NonDefaultPref will disqualify you upon next
648 // [G] While enrolled, becoming TemporaryRequirement will _not_ disqualify you,
649 // but the session status will prevent win32k lockdown from taking effect.
652 static const char kPrefWin32k
[] = "security.sandbox.content.win32k-disable";
654 // The current enrollment status as controlled by Normandy. This value is only
655 // stored in the default preference branch, and is not persisted across
656 // sessions by the preference service. It therefore isn't available early
657 // enough at startup, and needs to be synced to a preference in the user
658 // branch which is persisted across sessions.
659 static const char kPrefWin32kExperimentEnrollmentStatus
[] =
660 "security.sandbox.content.win32k-experiment.enrollmentStatus";
662 // The enrollment status to be used at browser startup. This automatically
663 // synced from the above enrollmentStatus preference whenever the latter is
664 // changed. We reused the Fission experiment enum - it can have any of the
665 // values defined in the `nsIXULRuntime_ExperimentStatus` enum _except_ rollout.
666 // Meanings are documented in the declaration of
667 // `nsIXULRuntime.fissionExperimentStatus`
668 static const char kPrefWin32kExperimentStartupEnrollmentStatus
[] =
669 "security.sandbox.content.win32k-experiment.startupEnrollmentStatus";
673 bool Win32kExperimentEnrolled() {
674 MOZ_ASSERT(XRE_IsParentProcess());
675 return gWin32kExperimentStatus
== nsIXULRuntime::eExperimentStatusControl
||
676 gWin32kExperimentStatus
== nsIXULRuntime::eExperimentStatusTreatment
;
679 } // namespace mozilla
681 static bool Win32kRequirementsUnsatisfied(
682 nsIXULRuntime::ContentWin32kLockdownState aStatus
) {
683 return aStatus
== nsIXULRuntime::ContentWin32kLockdownState::
684 OperatingSystemNotSupported
||
686 nsIXULRuntime::ContentWin32kLockdownState::MissingWebRender
||
688 nsIXULRuntime::ContentWin32kLockdownState::MissingRemoteWebGL
||
690 nsIXULRuntime::ContentWin32kLockdownState::DecodersArentRemote
;
693 static void Win32kExperimentDisqualify() {
694 MOZ_ASSERT(XRE_IsParentProcess());
695 Preferences::SetUint(kPrefWin32kExperimentEnrollmentStatus
,
696 nsIXULRuntime::eExperimentStatusDisqualified
);
699 static void OnWin32kEnrollmentStatusChanged(const char* aPref
, void* aData
) {
701 Preferences::GetUint(kPrefWin32kExperimentEnrollmentStatus
,
702 nsIXULRuntime::eExperimentStatusUnenrolled
);
703 auto newStatus
= newStatusInt
< nsIXULRuntime::eExperimentStatusCount
704 ? nsIXULRuntime::ExperimentStatus(newStatusInt
)
705 : nsIXULRuntime::eExperimentStatusDisqualified
;
707 // Set the startup pref for next browser start [D]
708 Preferences::SetUint(kPrefWin32kExperimentStartupEnrollmentStatus
, newStatus
);
712 // This observer is notified during `profile-before-change`, and ensures that
713 // the experiment enrollment status is synced over before the browser shuts
714 // down, even if it was not modified since win32k was initialized.
715 class Win32kEnrollmentStatusShutdownObserver final
: public nsIObserver
{
719 NS_IMETHOD
Observe(nsISupports
* aSubject
, const char* aTopic
,
720 const char16_t
* aData
) override
{
721 MOZ_ASSERT(!strcmp("profile-before-change", aTopic
));
722 OnWin32kEnrollmentStatusChanged(kPrefWin32kExperimentEnrollmentStatus
,
728 ~Win32kEnrollmentStatusShutdownObserver() = default;
730 NS_IMPL_ISUPPORTS(Win32kEnrollmentStatusShutdownObserver
, nsIObserver
)
733 static void OnWin32kChanged(const char* aPref
, void* aData
) {
734 // If we're actively enrolled in the Win32k experiment, disqualify the user
735 // from the experiment if the Win32k pref is modified. [F]
736 if (Win32kExperimentEnrolled() && Preferences::HasUserValue(kPrefWin32k
)) {
737 Win32kExperimentDisqualify();
744 void EnsureWin32kInitialized();
747 nsIXULRuntime::ContentWin32kLockdownState
GetLiveWin32kLockdownState() {
750 // HasUserValue The Pref functions can only be called on main thread
751 MOZ_ASSERT(NS_IsMainThread());
753 # ifdef MOZ_BACKGROUNDTASKS
754 if (BackgroundTasks::IsBackgroundTaskMode()) {
755 // Let's bail out before loading all the graphics libs.
756 return nsIXULRuntime::ContentWin32kLockdownState::DisabledByDefault
;
760 mozilla::EnsureWin32kInitialized();
761 gfxPlatform::GetPlatform();
764 return nsIXULRuntime::ContentWin32kLockdownState::DisabledBySafeMode
;
767 if (EnvHasValue("MOZ_ENABLE_WIN32K")) {
768 return nsIXULRuntime::ContentWin32kLockdownState::DisabledByEnvVar
;
771 if (!mozilla::BrowserTabsRemoteAutostart()) {
772 return nsIXULRuntime::ContentWin32kLockdownState::DisabledByE10S
;
775 // Win32k lockdown is available on Win8+, but we are initially limiting it to
776 // Windows 10 v1709 (build 16299) or later. Before this COM initialization
777 // currently fails if user32.dll has loaded before it is called.
778 if (!IsWin10FallCreatorsUpdateOrLater()) {
779 return nsIXULRuntime::ContentWin32kLockdownState::
780 OperatingSystemNotSupported
;
784 ConflictingMitigationStatus conflictingMitigationStatus
= {};
785 if (!detect_win32k_conflicting_mitigations(&conflictingMitigationStatus
)) {
786 return nsIXULRuntime::ContentWin32kLockdownState::
787 IncompatibleMitigationPolicy
;
789 if (conflictingMitigationStatus
.caller_check
||
790 conflictingMitigationStatus
.sim_exec
||
791 conflictingMitigationStatus
.stack_pivot
) {
792 return nsIXULRuntime::ContentWin32kLockdownState::
793 IncompatibleMitigationPolicy
;
797 // Win32k Lockdown requires Remote WebGL, but it may be disabled on
798 // certain hardware or virtual machines.
799 if (!gfx::gfxVars::AllowWebglOop() || !StaticPrefs::webgl_out_of_process()) {
800 return nsIXULRuntime::ContentWin32kLockdownState::MissingRemoteWebGL
;
803 // Some (not sure exactly which) decoders are not compatible
804 if (!PDMFactory::AllDecodersAreRemote()) {
805 return nsIXULRuntime::ContentWin32kLockdownState::DecodersArentRemote
;
809 Preferences::HasUserValue("security.sandbox.content.win32k-disable");
810 bool prefValue
= Preferences::GetBool(
811 "security.sandbox.content.win32k-disable", false, PrefValueKind::User
);
812 bool defaultValue
= Preferences::GetBool(
813 "security.sandbox.content.win32k-disable", false, PrefValueKind::Default
);
817 return nsIXULRuntime::ContentWin32kLockdownState::EnabledByUserPref
;
819 return nsIXULRuntime::ContentWin32kLockdownState::DisabledByUserPref
;
823 if (gWin32kExperimentStatus
==
824 nsIXULRuntime::ExperimentStatus::eExperimentStatusControl
) {
825 return nsIXULRuntime::ContentWin32kLockdownState::DisabledByControlGroup
;
826 } else if (gWin32kExperimentStatus
==
827 nsIXULRuntime::ExperimentStatus::eExperimentStatusTreatment
) {
828 return nsIXULRuntime::ContentWin32kLockdownState::EnabledByTreatmentGroup
;
832 return nsIXULRuntime::ContentWin32kLockdownState::EnabledByDefault
;
834 return nsIXULRuntime::ContentWin32kLockdownState::DisabledByDefault
;
839 return nsIXULRuntime::ContentWin32kLockdownState::OperatingSystemNotSupported
;
846 void EnsureWin32kInitialized() {
847 if (gWin32kInitialized
) {
850 gWin32kInitialized
= true;
854 // Initialize the Win32k experiment, configuring win32k's
855 // default, before checking other overrides. This allows opting-out of a
856 // Win32k experiment through about:preferences or about:config from a
858 uint32_t experimentRaw
=
859 Preferences::GetUint(kPrefWin32kExperimentStartupEnrollmentStatus
,
860 nsIXULRuntime::eExperimentStatusUnenrolled
);
861 gWin32kExperimentStatus
=
862 experimentRaw
< nsIXULRuntime::eExperimentStatusCount
863 ? nsIXULRuntime::ExperimentStatus(experimentRaw
)
864 : nsIXULRuntime::eExperimentStatusDisqualified
;
866 // Watch the experiment enrollment status pref to detect experiment
867 // disqualification, and ensure it is propagated for the next restart.
868 Preferences::RegisterCallback(&OnWin32kEnrollmentStatusChanged
,
869 kPrefWin32kExperimentEnrollmentStatus
);
870 if (nsCOMPtr
<nsIObserverService
> observerService
=
871 mozilla::services::GetObserverService()) {
872 nsCOMPtr
<nsIObserver
> shutdownObserver
=
873 new Win32kEnrollmentStatusShutdownObserver();
874 observerService
->AddObserver(shutdownObserver
, "profile-before-change",
878 // If the user no longer qualifies because they edited a required pref, check
880 auto tmpStatus
= GetLiveWin32kLockdownState();
881 if (Win32kExperimentEnrolled() && Win32kRequirementsUnsatisfied(tmpStatus
)) {
882 Win32kExperimentDisqualify();
883 gWin32kExperimentStatus
= nsIXULRuntime::eExperimentStatusDisqualified
;
886 // If the user has overridden an active experiment by setting a user value for
887 // "security.sandbox.content.win32k-disable", disqualify the user from the
888 // experiment. [A] [F]
889 if (Preferences::HasUserValue(kPrefWin32k
) && Win32kExperimentEnrolled()) {
890 Win32kExperimentDisqualify();
891 gWin32kExperimentStatus
= nsIXULRuntime::eExperimentStatusDisqualified
;
894 // Unlike Fission, we do not configure the default branch based on experiment
895 // enrollment status. Instead we check the startupEnrollmentPref in
896 // GetContentWin32kLockdownState()
898 Preferences::RegisterCallback(&OnWin32kChanged
, kPrefWin32k
);
901 gWin32kStatus
= GetLiveWin32kLockdownState();
905 nsIXULRuntime::ContentWin32kLockdownState::OperatingSystemNotSupported
;
906 gWin32kExperimentStatus
= nsIXULRuntime::eExperimentStatusUnenrolled
;
911 nsIXULRuntime::ContentWin32kLockdownState
GetWin32kLockdownState() {
914 mozilla::EnsureWin32kInitialized();
915 return gWin32kStatus
;
919 return nsIXULRuntime::ContentWin32kLockdownState::OperatingSystemNotSupported
;
924 } // namespace mozilla
926 // End Win32k Infrastructure ==========================================
928 // Fission Infrastructure =============================================
930 // Fission enablement for the current session is determined once, at startup,
931 // and then remains the same for the duration of the session.
933 // The following factors determine whether or not Fission is enabled for a
934 // session, in order of precedence:
936 // - Safe mode: In safe mode, Fission is never enabled.
938 // - The MOZ_FORCE_ENABLE_FISSION environment variable: If set to any value,
939 // Fission will be enabled.
941 // - The 'fission.autostart' preference, if it has been configured by the user.
942 static const char kPrefFissionAutostart
[] = "fission.autostart";
944 // The computed FissionAutostart value for the session, read by content
945 // processes to initialize gFissionAutostart.
947 // This pref is locked, and only configured on the default branch, so should
948 // never be persisted in a profile.
949 static const char kPrefFissionAutostartSession
[] = "fission.autostart.session";
952 // The computed FissionAutostart value for the session, read by content
953 // processes to initialize gFissionAutostart.
955 static bool gFissionAutostart
= false;
956 static bool gFissionAutostartInitialized
= false;
957 static nsIXULRuntime::FissionDecisionStatus gFissionDecisionStatus
;
958 static void EnsureFissionAutostartInitialized() {
959 if (gFissionAutostartInitialized
) {
962 gFissionAutostartInitialized
= true;
964 if (!XRE_IsParentProcess()) {
965 // This pref is configured for the current session by the parent process.
966 gFissionAutostart
= Preferences::GetBool(kPrefFissionAutostartSession
,
967 false, PrefValueKind::Default
);
971 if (!BrowserTabsRemoteAutostart()) {
972 gFissionAutostart
= false;
973 if (gBrowserTabsRemoteStatus
== kE10sForceDisabled
) {
974 gFissionDecisionStatus
= nsIXULRuntime::eFissionDisabledByE10sEnv
;
976 gFissionDecisionStatus
= nsIXULRuntime::eFissionDisabledByE10sOther
;
978 } else if (EnvHasValue("MOZ_FORCE_ENABLE_FISSION")) {
979 gFissionAutostart
= true;
980 gFissionDecisionStatus
= nsIXULRuntime::eFissionEnabledByEnv
;
981 } else if (EnvHasValue("MOZ_FORCE_DISABLE_FISSION")) {
982 gFissionAutostart
= false;
983 gFissionDecisionStatus
= nsIXULRuntime::eFissionDisabledByEnv
;
985 // NOTE: This will take into account changes to the default due to
986 // `InitializeFissionExperimentStatus`.
987 gFissionAutostart
= Preferences::GetBool(kPrefFissionAutostart
, false);
988 if (Preferences::HasUserValue(kPrefFissionAutostart
)) {
989 gFissionDecisionStatus
= gFissionAutostart
990 ? nsIXULRuntime::eFissionEnabledByUserPref
991 : nsIXULRuntime::eFissionDisabledByUserPref
;
993 gFissionDecisionStatus
= gFissionAutostart
994 ? nsIXULRuntime::eFissionEnabledByDefault
995 : nsIXULRuntime::eFissionDisabledByDefault
;
999 // Content processes cannot run the same logic as we're running in the parent
1000 // process, as the current value of various preferences may have changed
1001 // between launches. Instead, the content process will read the default branch
1002 // of the locked `fission.autostart.session` preference to determine the value
1003 // determined by this method.
1004 Preferences::Unlock(kPrefFissionAutostartSession
);
1005 Preferences::ClearUser(kPrefFissionAutostartSession
);
1006 Preferences::SetBool(kPrefFissionAutostartSession
, gFissionAutostart
,
1007 PrefValueKind::Default
);
1008 Preferences::Lock(kPrefFissionAutostartSession
);
1013 bool FissionAutostart() {
1014 EnsureFissionAutostartInitialized();
1015 return gFissionAutostart
;
1018 } // namespace mozilla
1020 // End Fission Infrastructure =========================================
1024 bool SessionHistoryInParent() {
1025 return FissionAutostart() ||
1027 fission_disableSessionHistoryInParent_AtStartup_DoNotUseDirectly();
1030 bool SessionStorePlatformCollection() {
1031 return SessionHistoryInParent() &&
1033 browser_sessionstore_disable_platform_collection_AtStartup_DoNotUseDirectly();
1036 bool BFCacheInParent() {
1037 return SessionHistoryInParent() &&
1038 StaticPrefs::fission_bfcacheInParent_DoNotUseDirectly();
1041 } // namespace mozilla
1044 * The nsXULAppInfo object implements nsIFactory so that it can be its own
1047 class nsXULAppInfo
: public nsIXULAppInfo
,
1049 public nsIWinAppHelper
,
1051 public nsICrashReporter
,
1052 public nsIFinishDumpingCallback
,
1053 public nsIXULRuntime
1057 constexpr nsXULAppInfo() = default;
1058 NS_DECL_ISUPPORTS_INHERITED
1059 NS_DECL_NSIPLATFORMINFO
1060 NS_DECL_NSIXULAPPINFO
1061 NS_DECL_NSIXULRUNTIME
1062 NS_DECL_NSICRASHREPORTER
1063 NS_DECL_NSIFINISHDUMPINGCALLBACK
1065 NS_DECL_NSIWINAPPHELPER
1069 NS_INTERFACE_MAP_BEGIN(nsXULAppInfo
)
1070 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsIXULRuntime
)
1071 NS_INTERFACE_MAP_ENTRY(nsIXULRuntime
)
1073 NS_INTERFACE_MAP_ENTRY(nsIWinAppHelper
)
1075 NS_INTERFACE_MAP_ENTRY(nsICrashReporter
)
1076 NS_INTERFACE_MAP_ENTRY(nsIFinishDumpingCallback
)
1077 NS_INTERFACE_MAP_ENTRY(nsIPlatformInfo
)
1078 NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIXULAppInfo
,
1079 gAppData
|| XRE_IsContentProcess())
1080 NS_INTERFACE_MAP_END
1082 NS_IMETHODIMP_(MozExternalRefCountType
)
1083 nsXULAppInfo::AddRef() { return 1; }
1085 NS_IMETHODIMP_(MozExternalRefCountType
)
1086 nsXULAppInfo::Release() { return 1; }
1089 nsXULAppInfo::GetVendor(nsACString
& aResult
) {
1090 if (XRE_IsContentProcess()) {
1091 ContentChild
* cc
= ContentChild::GetSingleton();
1092 aResult
= cc
->GetAppInfo().vendor
;
1095 aResult
.Assign(gAppData
->vendor
);
1101 nsXULAppInfo::GetName(nsACString
& aResult
) {
1102 if (XRE_IsContentProcess()) {
1103 ContentChild
* cc
= ContentChild::GetSingleton();
1104 aResult
= cc
->GetAppInfo().name
;
1108 #ifdef MOZ_WIDGET_ANDROID
1109 nsCString name
= java::GeckoAppShell::GetAppName()->ToCString();
1110 aResult
.Assign(std::move(name
));
1112 aResult
.Assign(gAppData
->name
);
1119 nsXULAppInfo::GetID(nsACString
& aResult
) {
1120 if (XRE_IsContentProcess()) {
1121 ContentChild
* cc
= ContentChild::GetSingleton();
1122 aResult
= cc
->GetAppInfo().ID
;
1125 aResult
.Assign(gAppData
->ID
);
1131 nsXULAppInfo::GetVersion(nsACString
& aResult
) {
1132 if (XRE_IsContentProcess()) {
1133 ContentChild
* cc
= ContentChild::GetSingleton();
1134 aResult
= cc
->GetAppInfo().version
;
1137 aResult
.Assign(gAppData
->version
);
1143 nsXULAppInfo::GetPlatformVersion(nsACString
& aResult
) {
1144 aResult
.Assign(gToolkitVersion
);
1150 nsXULAppInfo::GetAppBuildID(nsACString
& aResult
) {
1151 if (XRE_IsContentProcess()) {
1152 ContentChild
* cc
= ContentChild::GetSingleton();
1153 aResult
= cc
->GetAppInfo().buildID
;
1156 aResult
.Assign(gAppData
->buildID
);
1162 nsXULAppInfo::GetPlatformBuildID(nsACString
& aResult
) {
1163 aResult
.Assign(gToolkitBuildID
);
1169 nsXULAppInfo::GetUAName(nsACString
& aResult
) {
1170 if (XRE_IsContentProcess()) {
1171 ContentChild
* cc
= ContentChild::GetSingleton();
1172 aResult
= cc
->GetAppInfo().UAName
;
1175 aResult
.Assign(gAppData
->UAName
);
1181 nsXULAppInfo::GetSourceURL(nsACString
& aResult
) {
1182 if (XRE_IsContentProcess()) {
1183 ContentChild
* cc
= ContentChild::GetSingleton();
1184 aResult
= cc
->GetAppInfo().sourceURL
;
1187 aResult
.Assign(gAppData
->sourceURL
);
1193 nsXULAppInfo::GetUpdateURL(nsACString
& aResult
) {
1194 if (XRE_IsContentProcess()) {
1195 ContentChild
* cc
= ContentChild::GetSingleton();
1196 aResult
= cc
->GetAppInfo().updateURL
;
1199 aResult
.Assign(gAppData
->updateURL
);
1205 nsXULAppInfo::GetLogConsoleErrors(bool* aResult
) {
1206 *aResult
= gLogConsoleErrors
;
1211 nsXULAppInfo::SetLogConsoleErrors(bool aValue
) {
1212 gLogConsoleErrors
= aValue
;
1217 nsXULAppInfo::GetInSafeMode(bool* aResult
) {
1218 *aResult
= gSafeMode
;
1223 nsXULAppInfo::GetOS(nsACString
& aResult
) {
1224 aResult
.AssignLiteral(OS_TARGET
);
1229 nsXULAppInfo::GetXPCOMABI(nsACString
& aResult
) {
1230 #ifdef TARGET_XPCOM_ABI
1231 aResult
.AssignLiteral(TARGET_XPCOM_ABI
);
1234 return NS_ERROR_NOT_AVAILABLE
;
1239 nsXULAppInfo::GetWidgetToolkit(nsACString
& aResult
) {
1240 aResult
.AssignLiteral(MOZ_WIDGET_TOOLKIT
);
1244 // Ensure that the GeckoProcessType enum, defined in xpcom/build/nsXULAppAPI.h,
1245 // is synchronized with the const unsigned longs defined in
1246 // xpcom/system/nsIXULRuntime.idl.
1247 #define GECKO_PROCESS_TYPE(enum_value, enum_name, string_name, proc_typename, \
1248 process_bin_type, procinfo_typename, \
1249 webidl_typename, allcaps_name) \
1250 static_assert(nsIXULRuntime::PROCESS_TYPE_##allcaps_name == \
1251 static_cast<int>(GeckoProcessType_##enum_name), \
1252 "GeckoProcessType in nsXULAppAPI.h not synchronized with " \
1253 "nsIXULRuntime.idl");
1254 #include "mozilla/GeckoProcessTypes.h"
1255 #undef GECKO_PROCESS_TYPE
1257 // .. and ensure that that is all of them:
1258 static_assert(GeckoProcessType_Utility
+ 1 == GeckoProcessType_End
,
1259 "Did not find the final GeckoProcessType");
1262 nsXULAppInfo::GetProcessType(uint32_t* aResult
) {
1263 NS_ENSURE_ARG_POINTER(aResult
);
1264 *aResult
= XRE_GetProcessType();
1269 nsXULAppInfo::GetProcessID(uint32_t* aResult
) {
1271 *aResult
= GetCurrentProcessId();
1273 *aResult
= getpid();
1279 nsXULAppInfo::GetUniqueProcessID(uint64_t* aResult
) {
1280 if (XRE_IsContentProcess()) {
1281 ContentChild
* cc
= ContentChild::GetSingleton();
1282 *aResult
= cc
->GetID();
1290 nsXULAppInfo::GetRemoteType(nsACString
& aRemoteType
) {
1291 if (XRE_IsContentProcess()) {
1292 aRemoteType
= ContentChild::GetSingleton()->GetRemoteType();
1294 aRemoteType
= NOT_REMOTE_TYPE
;
1300 static nsCString gLastAppVersion
;
1301 static nsCString gLastAppBuildID
;
1304 nsXULAppInfo::GetLastAppVersion(nsACString
& aResult
) {
1305 if (XRE_IsContentProcess()) {
1306 return NS_ERROR_NOT_AVAILABLE
;
1309 if (!gLastAppVersion
.IsVoid() && gLastAppVersion
.IsEmpty()) {
1310 NS_WARNING("Attempt to retrieve lastAppVersion before it has been set.");
1311 return NS_ERROR_NOT_AVAILABLE
;
1314 aResult
.Assign(gLastAppVersion
);
1319 nsXULAppInfo::GetLastAppBuildID(nsACString
& aResult
) {
1320 if (XRE_IsContentProcess()) {
1321 return NS_ERROR_NOT_AVAILABLE
;
1324 if (!gLastAppBuildID
.IsVoid() && gLastAppBuildID
.IsEmpty()) {
1325 NS_WARNING("Attempt to retrieve lastAppBuildID before it has been set.");
1326 return NS_ERROR_NOT_AVAILABLE
;
1329 aResult
.Assign(gLastAppBuildID
);
1334 nsXULAppInfo::GetFissionAutostart(bool* aResult
) {
1335 *aResult
= FissionAutostart();
1340 nsXULAppInfo::GetWin32kExperimentStatus(ExperimentStatus
* aResult
) {
1341 if (!XRE_IsParentProcess()) {
1342 return NS_ERROR_NOT_AVAILABLE
;
1345 EnsureWin32kInitialized();
1346 *aResult
= gWin32kExperimentStatus
;
1351 nsXULAppInfo::GetWin32kLiveStatusTestingOnly(
1352 nsIXULRuntime::ContentWin32kLockdownState
* aResult
) {
1353 if (!XRE_IsParentProcess()) {
1354 return NS_ERROR_NOT_AVAILABLE
;
1357 EnsureWin32kInitialized();
1358 *aResult
= GetLiveWin32kLockdownState();
1363 nsXULAppInfo::GetWin32kSessionStatus(
1364 nsIXULRuntime::ContentWin32kLockdownState
* aResult
) {
1365 if (!XRE_IsParentProcess()) {
1366 return NS_ERROR_NOT_AVAILABLE
;
1369 EnsureWin32kInitialized();
1370 *aResult
= gWin32kStatus
;
1375 nsXULAppInfo::GetFissionDecisionStatus(FissionDecisionStatus
* aResult
) {
1376 if (!XRE_IsParentProcess()) {
1377 return NS_ERROR_NOT_AVAILABLE
;
1380 EnsureFissionAutostartInitialized();
1382 MOZ_ASSERT(gFissionDecisionStatus
!= eFissionStatusUnknown
);
1383 *aResult
= gFissionDecisionStatus
;
1388 nsXULAppInfo::GetFissionDecisionStatusString(nsACString
& aResult
) {
1389 if (!XRE_IsParentProcess()) {
1390 return NS_ERROR_NOT_AVAILABLE
;
1393 EnsureFissionAutostartInitialized();
1394 switch (gFissionDecisionStatus
) {
1395 case eFissionExperimentControl
:
1396 aResult
= "experimentControl";
1398 case eFissionExperimentTreatment
:
1399 aResult
= "experimentTreatment";
1401 case eFissionDisabledByE10sEnv
:
1402 aResult
= "disabledByE10sEnv";
1404 case eFissionEnabledByEnv
:
1405 aResult
= "enabledByEnv";
1407 case eFissionDisabledByEnv
:
1408 aResult
= "disabledByEnv";
1410 case eFissionEnabledByDefault
:
1411 aResult
= "enabledByDefault";
1413 case eFissionDisabledByDefault
:
1414 aResult
= "disabledByDefault";
1416 case eFissionEnabledByUserPref
:
1417 aResult
= "enabledByUserPref";
1419 case eFissionDisabledByUserPref
:
1420 aResult
= "disabledByUserPref";
1422 case eFissionDisabledByE10sOther
:
1423 aResult
= "disabledByE10sOther";
1425 case eFissionEnabledByRollout
:
1426 aResult
= "enabledByRollout";
1429 MOZ_ASSERT_UNREACHABLE("Unexpected enum value");
1435 nsXULAppInfo::GetSessionHistoryInParent(bool* aResult
) {
1436 *aResult
= SessionHistoryInParent();
1441 nsXULAppInfo::GetSessionStorePlatformCollection(bool* aResult
) {
1442 *aResult
= SessionStorePlatformCollection();
1447 nsXULAppInfo::GetBrowserTabsRemoteAutostart(bool* aResult
) {
1448 *aResult
= BrowserTabsRemoteAutostart();
1453 nsXULAppInfo::GetMaxWebProcessCount(uint32_t* aResult
) {
1454 *aResult
= mozilla::GetMaxWebProcessCount();
1459 nsXULAppInfo::GetAccessibilityEnabled(bool* aResult
) {
1460 #ifdef ACCESSIBILITY
1461 *aResult
= GetAccService() != nullptr;
1469 nsXULAppInfo::GetAccessibilityInstantiator(nsAString
& aInstantiator
) {
1470 #if defined(ACCESSIBILITY) && defined(XP_WIN)
1471 if (!GetAccService()) {
1472 aInstantiator
.Truncate();
1475 nsAutoString ipClientInfo
;
1476 a11y::Compatibility::GetHumanReadableConsumersStr(ipClientInfo
);
1477 aInstantiator
.Append(ipClientInfo
);
1478 aInstantiator
.AppendLiteral("|");
1480 nsCOMPtr
<nsIFile
> oopClientExe
;
1481 if (a11y::GetInstantiator(getter_AddRefs(oopClientExe
))) {
1482 nsAutoString oopClientInfo
;
1483 if (NS_SUCCEEDED(oopClientExe
->GetPath(oopClientInfo
))) {
1484 aInstantiator
.Append(oopClientInfo
);
1488 aInstantiator
.Truncate();
1494 nsXULAppInfo::GetIs64Bit(bool* aResult
) {
1495 #ifdef HAVE_64BIT_BUILD
1504 nsXULAppInfo::GetIsTextRecognitionSupported(bool* aResult
) {
1505 *aResult
= widget::TextRecognition::IsSupported();
1510 nsXULAppInfo::InvalidateCachesOnRestart() {
1511 nsCOMPtr
<nsIFile
> file
;
1513 NS_GetSpecialDirectory(NS_APP_PROFILE_DIR_STARTUP
, getter_AddRefs(file
));
1514 if (NS_FAILED(rv
)) return rv
;
1515 if (!file
) return NS_ERROR_NOT_AVAILABLE
;
1517 file
->AppendNative(FILE_COMPATIBILITY_INFO
);
1520 rv
= parser
.Init(file
);
1521 if (NS_FAILED(rv
)) {
1522 // This fails if compatibility.ini is not there, so we'll
1523 // flush the caches on the next restart anyways.
1528 rv
= parser
.GetString("Compatibility", "InvalidateCaches", buf
);
1530 if (NS_FAILED(rv
)) {
1532 rv
= file
->OpenNSPRFileDesc(PR_RDWR
| PR_APPEND
, 0600, &fd
);
1533 if (NS_FAILED(rv
)) {
1534 NS_ERROR("could not create output stream");
1535 return NS_ERROR_NOT_AVAILABLE
;
1537 static const char kInvalidationHeader
[] =
1538 NS_LINEBREAK
"InvalidateCaches=1" NS_LINEBREAK
;
1539 PR_Write(fd
, kInvalidationHeader
, sizeof(kInvalidationHeader
) - 1);
1546 nsXULAppInfo::GetReplacedLockTime(PRTime
* aReplacedLockTime
) {
1547 if (!gProfileLock
) return NS_ERROR_NOT_AVAILABLE
;
1548 gProfileLock
->GetReplacedLockTime(aReplacedLockTime
);
1553 nsXULAppInfo::GetDefaultUpdateChannel(nsACString
& aResult
) {
1554 aResult
.AssignLiteral(MOZ_STRINGIFY(MOZ_UPDATE_CHANNEL
));
1559 nsXULAppInfo::GetDistributionID(nsACString
& aResult
) {
1560 aResult
.AssignLiteral(MOZ_DISTRIBUTION_ID
);
1565 nsXULAppInfo::GetWindowsDLLBlocklistStatus(bool* aResult
) {
1566 #if defined(HAS_DLL_BLOCKLIST)
1567 *aResult
= DllBlocklist_CheckStatus();
1575 nsXULAppInfo::GetRestartedByOS(bool* aResult
) {
1576 *aResult
= gRestartedByOS
;
1581 nsXULAppInfo::GetChromeColorSchemeIsDark(bool* aResult
) {
1582 PreferenceSheet::EnsureInitialized();
1583 *aResult
= PreferenceSheet::ColorSchemeForChrome() == ColorScheme::Dark
;
1588 nsXULAppInfo::GetContentThemeDerivedColorSchemeIsDark(bool* aResult
) {
1590 PreferenceSheet::ThemeDerivedColorSchemeForContent() == ColorScheme::Dark
;
1595 nsXULAppInfo::GetPrefersReducedMotion(bool* aResult
) {
1597 LookAndFeel::GetInt(LookAndFeel::IntID::PrefersReducedMotion
, 0) == 1;
1602 nsXULAppInfo::GetDrawInTitlebar(bool* aResult
) {
1603 *aResult
= LookAndFeel::DrawInTitlebar();
1608 nsXULAppInfo::GetDesktopEnvironment(nsACString
& aDesktopEnvironment
) {
1609 #ifdef MOZ_WIDGET_GTK
1610 aDesktopEnvironment
.Assign(GetDesktopEnvironmentIdentifier());
1616 nsXULAppInfo::GetIsWayland(bool* aResult
) {
1617 #ifdef MOZ_WIDGET_GTK
1618 *aResult
= GdkIsWaylandDisplay();
1626 nsXULAppInfo::GetProcessStartupShortcut(nsAString
& aShortcut
) {
1628 if (XRE_IsParentProcess()) {
1629 aShortcut
.Assign(gProcessStartupShortcut
);
1633 return NS_ERROR_NOT_AVAILABLE
;
1636 #if defined(XP_WIN) && defined(MOZ_LAUNCHER_PROCESS)
1637 // Forward declaration
1638 void SetupLauncherProcessPref();
1640 static Maybe
<LauncherRegistryInfo::EnabledState
> gLauncherProcessState
;
1641 #endif // defined(XP_WIN) && defined(MOZ_LAUNCHER_PROCESS)
1644 nsXULAppInfo::GetLauncherProcessState(uint32_t* aResult
) {
1645 #if defined(XP_WIN) && defined(MOZ_LAUNCHER_PROCESS)
1646 SetupLauncherProcessPref();
1648 if (!gLauncherProcessState
) {
1649 return NS_ERROR_UNEXPECTED
;
1652 *aResult
= static_cast<uint32_t>(gLauncherProcessState
.value());
1655 return NS_ERROR_NOT_AVAILABLE
;
1661 nsXULAppInfo::GetUserCanElevate(bool* aUserCanElevate
) {
1663 if (!::OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY
, &rawToken
)) {
1664 *aUserCanElevate
= false;
1668 nsAutoHandle
token(rawToken
);
1669 LauncherResult
<TOKEN_ELEVATION_TYPE
> elevationType
= GetElevationType(token
);
1670 if (elevationType
.isErr()) {
1671 *aUserCanElevate
= false;
1675 // The possible values returned for elevationType and their meanings are:
1676 // TokenElevationTypeDefault: The token does not have a linked token
1677 // (e.g. UAC disabled or a standard user, so they can't be elevated)
1678 // TokenElevationTypeFull: The token is linked to an elevated token
1679 // (e.g. UAC is enabled and the user is already elevated so they can't
1680 // be elevated again)
1681 // TokenElevationTypeLimited: The token is linked to a limited token
1682 // (e.g. UAC is enabled and the user is not elevated, so they can be
1684 *aUserCanElevate
= (elevationType
.inspect() == TokenElevationTypeLimited
);
1690 nsXULAppInfo::GetCrashReporterEnabled(bool* aEnabled
) {
1691 *aEnabled
= CrashReporter::GetEnabled();
1696 nsXULAppInfo::SetEnabled(bool aEnabled
) {
1698 if (CrashReporter::GetEnabled()) {
1699 // no point in erroring for double-enabling
1703 nsCOMPtr
<nsIFile
> greBinDir
;
1704 NS_GetSpecialDirectory(NS_GRE_BIN_DIR
, getter_AddRefs(greBinDir
));
1706 return NS_ERROR_FAILURE
;
1709 nsCOMPtr
<nsIFile
> xreBinDirectory
= greBinDir
;
1710 if (!xreBinDirectory
) {
1711 return NS_ERROR_FAILURE
;
1714 return CrashReporter::SetExceptionHandler(xreBinDirectory
, true);
1717 if (!CrashReporter::GetEnabled()) {
1718 // no point in erroring for double-disabling
1722 return CrashReporter::UnsetExceptionHandler();
1726 nsXULAppInfo::GetServerURL(nsIURL
** aServerURL
) {
1727 NS_ENSURE_ARG_POINTER(aServerURL
);
1728 if (!CrashReporter::GetEnabled()) return NS_ERROR_NOT_INITIALIZED
;
1731 if (!CrashReporter::GetServerURL(data
)) {
1732 return NS_ERROR_FAILURE
;
1734 nsCOMPtr
<nsIURI
> uri
;
1735 NS_NewURI(getter_AddRefs(uri
), data
);
1736 if (!uri
) return NS_ERROR_FAILURE
;
1738 nsCOMPtr
<nsIURL
> url
;
1739 url
= do_QueryInterface(uri
);
1740 NS_ADDREF(*aServerURL
= url
);
1746 nsXULAppInfo::SetServerURL(nsIURL
* aServerURL
) {
1747 // Only allow https or http URLs
1748 if (!aServerURL
->SchemeIs("http") && !aServerURL
->SchemeIs("https")) {
1749 return NS_ERROR_INVALID_ARG
;
1753 nsresult rv
= aServerURL
->GetSpec(spec
);
1754 NS_ENSURE_SUCCESS(rv
, rv
);
1756 return CrashReporter::SetServerURL(spec
);
1760 nsXULAppInfo::GetMinidumpPath(nsIFile
** aMinidumpPath
) {
1761 if (!CrashReporter::GetEnabled()) return NS_ERROR_NOT_INITIALIZED
;
1764 if (!CrashReporter::GetMinidumpPath(path
)) return NS_ERROR_FAILURE
;
1766 nsresult rv
= NS_NewLocalFile(path
, false, aMinidumpPath
);
1767 NS_ENSURE_SUCCESS(rv
, rv
);
1772 nsXULAppInfo::SetMinidumpPath(nsIFile
* aMinidumpPath
) {
1774 nsresult rv
= aMinidumpPath
->GetPath(path
);
1775 NS_ENSURE_SUCCESS(rv
, rv
);
1776 return CrashReporter::SetMinidumpPath(path
);
1780 nsXULAppInfo::GetMinidumpForID(const nsAString
& aId
, nsIFile
** aMinidump
) {
1781 if (!CrashReporter::GetMinidumpForID(aId
, aMinidump
)) {
1782 return NS_ERROR_FILE_NOT_FOUND
;
1789 nsXULAppInfo::GetExtraFileForID(const nsAString
& aId
, nsIFile
** aExtraFile
) {
1790 if (!CrashReporter::GetExtraFileForID(aId
, aExtraFile
)) {
1791 return NS_ERROR_FILE_NOT_FOUND
;
1798 nsXULAppInfo::AnnotateCrashReport(const nsACString
& key
,
1799 const nsACString
& data
) {
1800 auto annotation
= CrashReporter::AnnotationFromString(key
);
1801 NS_ENSURE_TRUE(annotation
.isSome(), NS_ERROR_INVALID_ARG
);
1802 CrashReporter::RecordAnnotationNSCString(*annotation
, data
);
1807 nsXULAppInfo::RemoveCrashReportAnnotation(const nsACString
& key
) {
1808 auto annotation
= CrashReporter::AnnotationFromString(key
);
1809 NS_ENSURE_TRUE(annotation
.isSome(), NS_ERROR_INVALID_ARG
);
1810 CrashReporter::UnrecordAnnotation(*annotation
);
1815 nsXULAppInfo::IsAnnotationAllowedForPing(const nsACString
& aValue
,
1817 auto annotation
= CrashReporter::AnnotationFromString(aValue
);
1818 NS_ENSURE_TRUE(annotation
.isSome(), NS_ERROR_INVALID_ARG
);
1819 *aIsAllowed
= CrashReporter::IsAnnotationAllowedForPing(*annotation
);
1825 nsXULAppInfo::AppendAppNotesToCrashReport(const nsACString
& data
) {
1826 return CrashReporter::AppendAppNotesToCrashReport(data
);
1830 nsXULAppInfo::RegisterAppMemory(uint64_t pointer
, uint64_t len
) {
1831 return CrashReporter::RegisterAppMemory((void*)pointer
, len
);
1835 nsXULAppInfo::WriteMinidumpForException(void* aExceptionInfo
) {
1837 return CrashReporter::WriteMinidumpForException(
1838 static_cast<EXCEPTION_POINTERS
*>(aExceptionInfo
));
1840 return NS_ERROR_NOT_IMPLEMENTED
;
1845 nsXULAppInfo::AppendObjCExceptionInfoToAppNotes(void* aException
) {
1847 return CrashReporter::AppendObjCExceptionInfoToAppNotes(aException
);
1849 return NS_ERROR_NOT_IMPLEMENTED
;
1854 nsXULAppInfo::GetSubmitReports(bool* aEnabled
) {
1855 return CrashReporter::GetSubmitReports(aEnabled
);
1859 nsXULAppInfo::SetSubmitReports(bool aEnabled
) {
1860 return CrashReporter::SetSubmitReports(aEnabled
);
1864 nsXULAppInfo::UpdateCrashEventsDir() {
1865 CrashReporter::UpdateCrashEventsDir();
1870 nsXULAppInfo::SaveMemoryReport() {
1871 if (!CrashReporter::GetEnabled()) {
1872 return NS_ERROR_NOT_INITIALIZED
;
1874 nsCOMPtr
<nsIFile
> file
;
1875 nsresult rv
= CrashReporter::GetDefaultMemoryReportFile(getter_AddRefs(file
));
1876 if (NS_WARN_IF(NS_FAILED(rv
))) {
1881 file
->GetPath(path
);
1883 nsCOMPtr
<nsIMemoryInfoDumper
> dumper
=
1884 do_GetService("@mozilla.org/memory-info-dumper;1");
1885 if (NS_WARN_IF(!dumper
)) {
1886 return NS_ERROR_UNEXPECTED
;
1889 rv
= dumper
->DumpMemoryReportsToNamedFile(
1890 path
, this, file
, true /* anonymize */, false /* minimizeMemoryUsage */);
1891 if (NS_WARN_IF(NS_FAILED(rv
))) {
1897 // This method is from nsIFInishDumpingCallback.
1899 nsXULAppInfo::Callback(nsISupports
* aData
) {
1900 nsCOMPtr
<nsIFile
> file
= do_QueryInterface(aData
);
1903 CrashReporter::SetMemoryReportFile(file
);
1907 static const nsXULAppInfo kAppInfo
;
1909 nsresult
AppInfoConstructor(REFNSIID aIID
, void** aResult
) {
1910 return const_cast<nsXULAppInfo
*>(&kAppInfo
)->QueryInterface(aIID
, aResult
);
1912 } // namespace mozilla
1914 bool gLogConsoleErrors
= false;
1916 #define NS_ENSURE_TRUE_LOG(x, ret) \
1918 if (MOZ_UNLIKELY(!(x))) { \
1919 NS_WARNING("NS_ENSURE_TRUE(" #x ") failed"); \
1920 gLogConsoleErrors = true; \
1925 #define NS_ENSURE_SUCCESS_LOG(res, ret) \
1926 NS_ENSURE_TRUE_LOG(NS_SUCCEEDED(res), ret)
1929 * Because we're starting/stopping XPCOM several times in different scenarios,
1930 * this class is a stack-based critter that makes sure that XPCOM is shut down
1931 * during early returns.
1934 class ScopedXPCOMStartup
{
1936 ScopedXPCOMStartup() : mServiceManager(nullptr) {}
1937 ~ScopedXPCOMStartup();
1939 nsresult
Initialize(bool aInitJSContext
= true);
1940 nsresult
SetWindowCreator(nsINativeAppSupport
* native
);
1943 nsIServiceManager
* mServiceManager
;
1944 static nsINativeAppSupport
* gNativeAppSupport
;
1946 friend already_AddRefed
<nsINativeAppSupport
> NS_GetNativeAppSupport();
1949 ScopedXPCOMStartup::~ScopedXPCOMStartup() {
1950 NS_IF_RELEASE(gNativeAppSupport
);
1952 if (mServiceManager
) {
1954 // On OS X, we need a pool to catch cocoa objects that are autoreleased
1956 mozilla::MacAutoreleasePool pool
;
1959 nsCOMPtr
<nsIAppStartup
> appStartup(components::AppStartup::Service());
1960 if (appStartup
) appStartup
->DestroyHiddenWindow();
1962 gDirServiceProvider
->DoShutdown();
1963 PROFILER_MARKER_UNTYPED("Shutdown early", OTHER
);
1967 NS_ShutdownXPCOM(mServiceManager
);
1968 mServiceManager
= nullptr;
1972 nsresult
ScopedXPCOMStartup::Initialize(bool aInitJSContext
) {
1973 NS_ASSERTION(gDirServiceProvider
, "Should not get here!");
1977 rv
= NS_InitXPCOM(&mServiceManager
, gDirServiceProvider
->GetAppDir(),
1978 gDirServiceProvider
, aInitJSContext
);
1979 if (NS_FAILED(rv
)) {
1980 NS_ERROR("Couldn't start xpcom!");
1981 mServiceManager
= nullptr;
1984 nsCOMPtr
<nsIComponentRegistrar
> reg
= do_QueryInterface(mServiceManager
);
1985 NS_ASSERTION(reg
, "Service Manager doesn't QI to Registrar.");
1993 * This is a little factory class that serves as a singleton-service-factory
1994 * for the nativeappsupport object.
1996 class nsSingletonFactory final
: public nsIFactory
{
2001 explicit nsSingletonFactory(nsISupports
* aSingleton
);
2004 ~nsSingletonFactory() = default;
2005 nsCOMPtr
<nsISupports
> mSingleton
;
2008 nsSingletonFactory::nsSingletonFactory(nsISupports
* aSingleton
)
2009 : mSingleton(aSingleton
) {
2010 NS_ASSERTION(mSingleton
, "Singleton was null!");
2013 NS_IMPL_ISUPPORTS(nsSingletonFactory
, nsIFactory
)
2016 nsSingletonFactory::CreateInstance(const nsIID
& aIID
, void** aResult
) {
2017 return mSingleton
->QueryInterface(aIID
, aResult
);
2021 * Set our windowcreator on the WindowWatcher service.
2023 nsresult
ScopedXPCOMStartup::SetWindowCreator(nsINativeAppSupport
* native
) {
2026 NS_IF_ADDREF(gNativeAppSupport
= native
);
2028 nsCOMPtr
<nsIWindowCreator
> creator(components::AppStartup::Service());
2029 if (!creator
) return NS_ERROR_UNEXPECTED
;
2031 nsCOMPtr
<nsIWindowWatcher
> wwatch(
2032 do_GetService(NS_WINDOWWATCHER_CONTRACTID
, &rv
));
2033 NS_ENSURE_SUCCESS(rv
, rv
);
2035 return wwatch
->SetWindowCreator(creator
);
2038 /* static */ already_AddRefed
<nsINativeAppSupport
> NS_GetNativeAppSupport() {
2039 if (!ScopedXPCOMStartup::gNativeAppSupport
) {
2043 return do_AddRef(ScopedXPCOMStartup::gNativeAppSupport
);
2046 #ifdef MOZ_HAS_REMOTE
2047 /* static */ already_AddRefed
<nsIRemoteService
> GetRemoteService() {
2048 nsCOMPtr
<nsIRemoteService
> remoteService
= gRemoteService
.get();
2049 return remoteService
.forget();
2053 nsINativeAppSupport
* ScopedXPCOMStartup::gNativeAppSupport
;
2055 static void DumpArbitraryHelp() {
2061 ScopedXPCOMStartup xpcom
;
2064 nsCOMPtr
<nsICommandLineRunner
> cmdline(new nsCommandLine());
2067 rv
= cmdline
->GetHelpText(text
);
2068 if (NS_SUCCEEDED(rv
)) printf("%s", text
.get());
2072 // English text needs to go into a dtd file.
2073 // But when this is called we have no components etc. These strings must either
2074 // be here, or in a native resource file.
2075 static void DumpHelp() {
2077 "Usage: %s [ options ... ] [URL]\n"
2078 " where options include:\n\n",
2084 " --display=DISPLAY X display to use\n"
2085 " --sync Make X calls synchronous\n");
2089 " --g-fatal-warnings Make all warnings fatal\n"
2091 (const char*)gAppData
->name
);
2095 " -h or --help Print this message.\n"
2096 " -v or --version Print %s version.\n"
2097 " --full-version Print %s version, build and platform build ids.\n"
2098 " -P <profile> Start with <profile>.\n"
2099 " --profile <path> Start with profile at <path>.\n"
2100 " --migration Start with migration wizard.\n"
2101 " --ProfileManager Start with ProfileManager.\n"
2102 " --origin-to-force-quic-on <origin>\n"
2103 " Force to use QUIC for the specified origin.\n"
2104 #ifdef MOZ_HAS_REMOTE
2105 " --new-instance Open new instance, not a new window in running "
2108 " --safe-mode Disables extensions and themes for this session.\n"
2109 #ifdef MOZ_BLOCK_PROFILE_DOWNGRADE
2110 " --allow-downgrade Allows downgrading a profile.\n"
2112 " --MOZ_LOG=<modules> Treated as MOZ_LOG=<modules> environment "
2115 " --MOZ_LOG_FILE=<file> Treated as MOZ_LOG_FILE=<file> environment "
2117 " overrides it. If MOZ_LOG_FILE is not specified as "
2119 " argument or as an environment variable, logging "
2121 " written to stdout.\n",
2122 (const char*)gAppData
->name
, (const char*)gAppData
->name
);
2125 printf(" --console Start %s with a debugging console.\n",
2126 (const char*)gAppData
->name
);
2129 #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) || defined(XP_MACOSX)
2130 printf(" --headless Run without a GUI.\n");
2133 #if defined(MOZ_ENABLE_DBUS)
2135 " --dbus-service <launcher> Run as DBus service for "
2136 "org.freedesktop.Application and\n"
2137 " set a launcher (usually /usr/bin/appname "
2141 // this works, but only after the components have registered. so if you drop
2142 // in a new command line handler, --help won't not until the second run. out
2143 // of the bug, because we ship a component.reg file, it works correctly.
2144 DumpArbitraryHelp();
2147 static inline void DumpVersion() {
2148 if (gAppData
->vendor
&& *gAppData
->vendor
) {
2149 printf("%s ", (const char*)gAppData
->vendor
);
2151 printf("%s ", (const char*)gAppData
->name
);
2153 // Use the displayed version
2154 // For example, for beta, we would display 42.0b2 instead of 42.0
2155 printf("%s", MOZ_STRINGIFY(MOZ_APP_VERSION_DISPLAY
));
2157 if (gAppData
->copyright
&& *gAppData
->copyright
) {
2158 printf(", %s", (const char*)gAppData
->copyright
);
2163 static inline void DumpFullVersion() {
2164 if (gAppData
->vendor
&& *gAppData
->vendor
) {
2165 printf("%s ", (const char*)gAppData
->vendor
);
2167 printf("%s ", (const char*)gAppData
->name
);
2169 // Use the displayed version
2170 // For example, for beta, we would display 42.0b2 instead of 42.0
2171 printf("%s ", MOZ_STRINGIFY(MOZ_APP_VERSION_DISPLAY
));
2173 printf("%s ", (const char*)gAppData
->buildID
);
2174 printf("%s ", (const char*)PlatformBuildID());
2175 if (gAppData
->copyright
&& *gAppData
->copyright
) {
2176 printf(", %s", (const char*)gAppData
->copyright
);
2181 void XRE_InitOmnijar(nsIFile
* greOmni
, nsIFile
* appOmni
) {
2182 mozilla::Omnijar::Init(greOmni
, appOmni
);
2185 nsresult
XRE_GetBinaryPath(nsIFile
** aResult
) {
2186 return mozilla::BinaryPath::GetFile(aResult
);
2190 # include "nsWindowsRestart.cpp"
2191 # include <shellapi.h>
2193 typedef BOOL(WINAPI
* SetProcessDEPPolicyFunc
)(DWORD dwFlags
);
2195 static void RegisterApplicationRestartChanged(const char* aPref
, void* aData
) {
2196 DWORD cchCmdLine
= 0;
2197 HRESULT rc
= ::GetApplicationRestartSettings(::GetCurrentProcess(), nullptr,
2198 &cchCmdLine
, nullptr);
2199 bool wasRegistered
= false;
2201 wasRegistered
= true;
2204 if (Preferences::GetBool(PREF_WIN_REGISTER_APPLICATION_RESTART
, false) &&
2206 // Make the command line to use when restarting.
2207 // Excludes argv[0] because RegisterApplicationRestart adds the
2208 // executable name, replace that temporarily with -os-restarted
2209 char* exeName
= gRestartArgv
[0];
2210 gRestartArgv
[0] = const_cast<char*>("-os-restarted");
2211 wchar_t** restartArgvConverted
=
2212 AllocConvertUTF8toUTF16Strings(gRestartArgc
, gRestartArgv
);
2213 gRestartArgv
[0] = exeName
;
2215 mozilla::UniquePtr
<wchar_t[]> restartCommandLine
;
2216 if (restartArgvConverted
) {
2217 restartCommandLine
=
2218 mozilla::MakeCommandLine(gRestartArgc
, restartArgvConverted
);
2219 FreeAllocStrings(gRestartArgc
, restartArgvConverted
);
2222 if (restartCommandLine
) {
2223 // Flags RESTART_NO_PATCH and RESTART_NO_REBOOT are not set, so we
2224 // should be restarted if terminated by an update or restart.
2225 ::RegisterApplicationRestart(restartCommandLine
.get(),
2226 RESTART_NO_CRASH
| RESTART_NO_HANG
);
2228 } else if (wasRegistered
) {
2229 ::UnregisterApplicationRestart();
2233 static void OnAlteredPrefetchPrefChanged(const char* aPref
, void* aData
) {
2234 int32_t prefVal
= Preferences::GetInt(PREF_WIN_ALTERED_DLL_PREFETCH
, 0);
2236 mozilla::DllPrefetchExperimentRegistryInfo prefetchRegInfo
;
2237 mozilla::DebugOnly
<mozilla::Result
<Ok
, nsresult
>> reflectResult
=
2238 prefetchRegInfo
.ReflectPrefToRegistry(prefVal
);
2240 MOZ_ASSERT(reflectResult
.value
.isOk());
2243 static void SetupAlteredPrefetchPref() {
2244 mozilla::DllPrefetchExperimentRegistryInfo prefetchRegInfo
;
2246 mozilla::DebugOnly
<mozilla::Result
<Ok
, nsresult
>> reflectResult
=
2247 prefetchRegInfo
.ReflectPrefToRegistry(
2248 Preferences::GetInt(PREF_WIN_ALTERED_DLL_PREFETCH
, 0));
2249 MOZ_ASSERT(reflectResult
.value
.isOk());
2251 Preferences::RegisterCallback(&OnAlteredPrefetchPrefChanged
,
2252 PREF_WIN_ALTERED_DLL_PREFETCH
);
2255 static void ReflectSkeletonUIPrefToRegistry(const char* aPref
, void* aData
) {
2259 bool shouldBeEnabled
=
2260 Preferences::GetBool(kPrefPreXulSkeletonUI
, false) &&
2261 Preferences::GetBool(kPrefBrowserStartupBlankWindow
, false) &&
2262 LookAndFeel::DrawInTitlebar();
2263 if (shouldBeEnabled
&& Preferences::HasUserValue(kPrefThemeId
)) {
2265 Preferences::GetCString(kPrefThemeId
, themeId
);
2266 if (themeId
.EqualsLiteral("default-theme@mozilla.org")) {
2267 Unused
<< SetPreXULSkeletonUIThemeId(ThemeMode::Default
);
2268 } else if (themeId
.EqualsLiteral("firefox-compact-dark@mozilla.org")) {
2269 Unused
<< SetPreXULSkeletonUIThemeId(ThemeMode::Dark
);
2270 } else if (themeId
.EqualsLiteral("firefox-compact-light@mozilla.org")) {
2271 Unused
<< SetPreXULSkeletonUIThemeId(ThemeMode::Light
);
2273 shouldBeEnabled
= false;
2275 } else if (shouldBeEnabled
) {
2276 Unused
<< SetPreXULSkeletonUIThemeId(ThemeMode::Default
);
2279 if (GetPreXULSkeletonUIEnabled() != shouldBeEnabled
) {
2280 Unused
<< SetPreXULSkeletonUIEnabledIfAllowed(shouldBeEnabled
);
2284 static void SetupSkeletonUIPrefs() {
2285 ReflectSkeletonUIPrefToRegistry(nullptr, nullptr);
2286 Preferences::RegisterCallback(&ReflectSkeletonUIPrefToRegistry
,
2287 kPrefPreXulSkeletonUI
);
2288 Preferences::RegisterCallback(&ReflectSkeletonUIPrefToRegistry
,
2289 kPrefBrowserStartupBlankWindow
);
2290 Preferences::RegisterCallback(&ReflectSkeletonUIPrefToRegistry
, kPrefThemeId
);
2291 Preferences::RegisterCallback(
2292 &ReflectSkeletonUIPrefToRegistry
,
2293 nsDependentCString(StaticPrefs::GetPrefName_browser_tabs_inTitlebar()));
2296 # if defined(MOZ_LAUNCHER_PROCESS)
2298 static void OnLauncherPrefChanged(const char* aPref
, void* aData
) {
2299 bool prefVal
= Preferences::GetBool(PREF_WIN_LAUNCHER_PROCESS_ENABLED
, true);
2301 mozilla::LauncherRegistryInfo launcherRegInfo
;
2302 mozilla::DebugOnly
<mozilla::LauncherVoidResult
> reflectResult
=
2303 launcherRegInfo
.ReflectPrefToRegistry(prefVal
);
2304 MOZ_ASSERT(reflectResult
.inspect().isOk());
2307 static void OnLauncherTelemetryPrefChanged(const char* aPref
, void* aData
) {
2308 bool prefVal
= Preferences::GetBool(kPrefHealthReportUploadEnabled
, true);
2310 mozilla::LauncherRegistryInfo launcherRegInfo
;
2311 mozilla::DebugOnly
<mozilla::LauncherVoidResult
> reflectResult
=
2312 launcherRegInfo
.ReflectTelemetryPrefToRegistry(prefVal
);
2313 MOZ_ASSERT(reflectResult
.inspect().isOk());
2316 static void SetupLauncherProcessPref() {
2317 if (gLauncherProcessState
) {
2318 // We've already successfully run
2322 mozilla::LauncherRegistryInfo launcherRegInfo
;
2324 mozilla::LauncherResult
<mozilla::LauncherRegistryInfo::EnabledState
>
2325 enabledState
= launcherRegInfo
.IsEnabled();
2327 if (enabledState
.isOk()) {
2328 gLauncherProcessState
= Some(enabledState
.unwrap());
2330 CrashReporter::RecordAnnotationU32(
2331 CrashReporter::Annotation::LauncherProcessState
,
2332 static_cast<uint32_t>(enabledState
.unwrap()));
2334 // Reflect the launcher process registry state into user prefs
2335 Preferences::SetBool(
2336 PREF_WIN_LAUNCHER_PROCESS_ENABLED
,
2337 enabledState
.unwrap() !=
2338 mozilla::LauncherRegistryInfo::EnabledState::ForceDisabled
);
2341 mozilla::DebugOnly
<mozilla::LauncherVoidResult
> reflectResult
=
2342 launcherRegInfo
.ReflectTelemetryPrefToRegistry(
2343 Preferences::GetBool(kPrefHealthReportUploadEnabled
, true));
2344 MOZ_ASSERT(reflectResult
.inspect().isOk());
2346 Preferences::RegisterCallback(&OnLauncherPrefChanged
,
2347 PREF_WIN_LAUNCHER_PROCESS_ENABLED
);
2348 Preferences::RegisterCallback(&OnLauncherTelemetryPrefChanged
,
2349 kPrefHealthReportUploadEnabled
);
2352 # endif // defined(MOZ_LAUNCHER_PROCESS)
2354 # if defined(MOZ_DEFAULT_BROWSER_AGENT)
2356 # define DEFAULT_BROWSER_AGENT_KEY_NAME \
2357 "SOFTWARE\\" MOZ_APP_VENDOR "\\" MOZ_APP_NAME "\\Default Browser Agent"
2359 static nsresult
PrependRegistryValueName(nsAutoString
& aValueName
) {
2362 nsCOMPtr
<nsIFile
> binaryPath
;
2363 rv
= XRE_GetBinaryPath(getter_AddRefs(binaryPath
));
2364 NS_ENSURE_SUCCESS(rv
, rv
);
2366 nsCOMPtr
<nsIFile
> binaryDir
;
2367 rv
= binaryPath
->GetParent(getter_AddRefs(binaryDir
));
2368 NS_ENSURE_SUCCESS(rv
, rv
);
2370 nsAutoString prefix
;
2371 rv
= binaryDir
->GetPath(prefix
);
2372 NS_ENSURE_SUCCESS(rv
, rv
);
2374 prefix
.AppendLiteral("|");
2375 aValueName
.Insert(prefix
, 0);
2380 static void OnDefaultAgentTelemetryPrefChanged(const char* aPref
, void* aData
) {
2382 nsAutoString valueName
;
2383 if (strcmp(aPref
, kPrefHealthReportUploadEnabled
) == 0) {
2384 valueName
.AssignLiteral("DisableTelemetry");
2385 } else if (strcmp(aPref
, kPrefDefaultAgentEnabled
) == 0) {
2386 valueName
.AssignLiteral("DisableDefaultBrowserAgent");
2390 rv
= PrependRegistryValueName(valueName
);
2391 NS_ENSURE_SUCCESS_VOID(rv
);
2393 nsCOMPtr
<nsIWindowsRegKey
> regKey
=
2394 do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv
);
2395 NS_ENSURE_SUCCESS_VOID(rv
);
2397 nsAutoString keyName
;
2398 keyName
.AppendLiteral(DEFAULT_BROWSER_AGENT_KEY_NAME
);
2399 rv
= regKey
->Create(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER
, keyName
,
2400 nsIWindowsRegKey::ACCESS_WRITE
);
2402 bool prefVal
= Preferences::GetBool(aPref
, true);
2404 // We're recording whether the pref is *disabled*, so invert the value.
2405 rv
= regKey
->WriteIntValue(valueName
, prefVal
? 0 : 1);
2406 NS_ENSURE_SUCCESS_VOID(rv
);
2409 static void OnSetDefaultBrowserUserChoicePrefChanged(const char* aPref
,
2412 if (strcmp(aPref
, kPrefSetDefaultBrowserUserChoicePref
) != 0) {
2415 nsAutoString valueName
;
2416 valueName
.AssignLiteral("SetDefaultBrowserUserChoice");
2417 rv
= PrependRegistryValueName(valueName
);
2418 NS_ENSURE_SUCCESS_VOID(rv
);
2420 nsCOMPtr
<nsIWindowsRegKey
> regKey
=
2421 do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv
);
2422 NS_ENSURE_SUCCESS_VOID(rv
);
2424 nsAutoString keyName
;
2425 keyName
.AppendLiteral(DEFAULT_BROWSER_AGENT_KEY_NAME
);
2426 rv
= regKey
->Create(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER
, keyName
,
2427 nsIWindowsRegKey::ACCESS_WRITE
);
2429 bool prefVal
= Preferences::GetBool(aPref
, true);
2431 rv
= regKey
->WriteIntValue(valueName
, prefVal
);
2432 NS_ENSURE_SUCCESS_VOID(rv
);
2435 static void OnDefaultAgentRemoteSettingsPrefChanged(const char* aPref
,
2438 nsAutoString valueName
;
2439 if (strcmp(aPref
, kPrefServicesSettingsServer
) == 0) {
2440 valueName
.AssignLiteral("ServicesSettingsServer");
2444 rv
= PrependRegistryValueName(valueName
);
2445 NS_ENSURE_SUCCESS_VOID(rv
);
2447 nsCOMPtr
<nsIWindowsRegKey
> regKey
=
2448 do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv
);
2449 NS_ENSURE_SUCCESS_VOID(rv
);
2451 nsAutoString keyName
;
2452 keyName
.AppendLiteral(DEFAULT_BROWSER_AGENT_KEY_NAME
);
2453 rv
= regKey
->Create(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER
, keyName
,
2454 nsIWindowsRegKey::ACCESS_WRITE
);
2456 NS_ENSURE_SUCCESS_VOID(rv
);
2458 nsAutoString prefVal
;
2459 rv
= Preferences::GetString(aPref
, prefVal
);
2460 if (NS_FAILED(rv
)) {
2464 if (prefVal
.IsEmpty()) {
2465 rv
= regKey
->RemoveValue(valueName
);
2467 rv
= regKey
->WriteStringValue(valueName
, prefVal
);
2469 NS_ENSURE_SUCCESS_VOID(rv
);
2472 static void SetDefaultAgentLastRunTime() {
2474 nsAutoString valueName
;
2475 valueName
.AppendLiteral("AppLastRunTime");
2476 rv
= PrependRegistryValueName(valueName
);
2477 NS_ENSURE_SUCCESS_VOID(rv
);
2479 nsCOMPtr
<nsIWindowsRegKey
> regKey
=
2480 do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv
);
2481 NS_ENSURE_SUCCESS_VOID(rv
);
2483 nsAutoString keyName
;
2484 keyName
.AppendLiteral(DEFAULT_BROWSER_AGENT_KEY_NAME
);
2485 rv
= regKey
->Create(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER
, keyName
,
2486 nsIWindowsRegKey::ACCESS_WRITE
);
2487 NS_ENSURE_SUCCESS_VOID(rv
);
2490 GetSystemTimeAsFileTime(&fileTime
);
2492 ULARGE_INTEGER integerTime
;
2493 integerTime
.u
.LowPart
= fileTime
.dwLowDateTime
;
2494 integerTime
.u
.HighPart
= fileTime
.dwHighDateTime
;
2496 rv
= regKey
->WriteInt64Value(valueName
, integerTime
.QuadPart
);
2497 NS_ENSURE_SUCCESS_VOID(rv
);
2500 # endif // defined(MOZ_DEFAULT_BROWSER_AGENT)
2504 void UnlockProfile() {
2506 gProfileLock
->Unlock();
2510 nsresult
LaunchChild(bool aBlankCommandLine
, bool aTryExec
) {
2511 // Restart this process by exec'ing it into the current process
2512 // if supported by the platform. Otherwise, use NSPR.
2515 // make sure JPROF doesn't think we're E10s
2516 unsetenv("JPROF_ISCHILD");
2519 if (aBlankCommandLine
) {
2521 gRestartArgv
[gRestartArgc
] = nullptr;
2524 SaveToEnv("MOZ_LAUNCHED_CHILD=1");
2525 #if defined(MOZ_LAUNCHER_PROCESS)
2526 SaveToEnv("MOZ_LAUNCHER_PROCESS=1");
2527 #endif // defined(MOZ_LAUNCHER_PROCESS)
2529 #if !defined(MOZ_WIDGET_ANDROID) // Android has separate restart code.
2530 # if defined(XP_MACOSX)
2532 CommandLineServiceMac::SetupMacCommandLine(gRestartArgc
, gRestartArgv
, true);
2533 LaunchMacApp(gRestartArgc
, gRestartArgv
);
2535 nsCOMPtr
<nsIFile
> lf
;
2536 nsresult rv
= XRE_GetBinaryPath(getter_AddRefs(lf
));
2537 if (NS_FAILED(rv
)) return rv
;
2539 # if defined(XP_WIN)
2540 nsAutoString exePath
;
2541 rv
= lf
->GetPath(exePath
);
2542 if (NS_FAILED(rv
)) return rv
;
2545 if (!WinLaunchChild(exePath
.get(), gRestartArgc
, gRestartArgv
, nullptr,
2547 return NS_ERROR_FAILURE
;
2548 // Keep the current process around until the restarted process has created
2549 // its message queue, to avoid the launched process's windows being forced
2550 // into the background.
2551 mozilla::WaitForInputIdle(hProcess
);
2552 ::CloseHandle(hProcess
);
2555 nsAutoCString exePath
;
2556 rv
= lf
->GetNativePath(exePath
);
2557 if (NS_FAILED(rv
)) return rv
;
2559 # if defined(XP_UNIX)
2561 execv(exePath
.get(), gRestartArgv
);
2563 // If execv returns we know it's because it failed.
2564 return NS_ERROR_FAILURE
;
2567 if (PR_CreateProcessDetached(exePath
.get(), gRestartArgv
, nullptr, nullptr) ==
2569 return NS_ERROR_FAILURE
;
2572 // Note that we don't know if the child process starts okay, if it
2573 // immediately returns non-zero then we may mask that by returning a zero
2577 # endif // WP_MACOSX
2578 #endif // MOZ_WIDGET_ANDROID
2580 return NS_ERROR_LAUNCHED_CHILD_PROCESS
;
2583 static const char kProfileProperties
[] =
2584 "chrome://mozapps/locale/profile/profileSelection.properties";
2589 * This class, instead of a raw nsresult, should be the return type of any
2590 * function called by SelectProfile that initializes XPCOM.
2592 class ReturnAbortOnError
{
2594 MOZ_IMPLICIT
ReturnAbortOnError(nsresult aRv
) { mRv
= ConvertRv(aRv
); }
2596 operator nsresult() { return mRv
; }
2599 inline nsresult
ConvertRv(nsresult aRv
) {
2600 if (NS_SUCCEEDED(aRv
) || aRv
== NS_ERROR_LAUNCHED_CHILD_PROCESS
) {
2603 #ifdef MOZ_BACKGROUNDTASKS
2604 // A background task that fails to lock its profile will return
2605 // NS_ERROR_UNEXPECTED and this will allow the task to exit with a
2606 // non-zero exit code.
2607 if (aRv
== NS_ERROR_UNEXPECTED
&& BackgroundTasks::IsBackgroundTaskMode()) {
2611 return NS_ERROR_ABORT
;
2619 static nsresult
ProfileMissingDialog(nsINativeAppSupport
* aNative
) {
2620 #ifdef MOZ_WIDGET_ANDROID
2621 // We cannot really do anything this early during initialization, so we just
2622 // return as this is likely the effect of misconfiguration on the test side.
2623 // Non-test code paths cannot set the profile folder, which is always the
2625 Output(true, "Could not find profile folder.\n");
2626 return NS_ERROR_ABORT
;
2628 # ifdef MOZ_BACKGROUNDTASKS
2629 if (BackgroundTasks::IsBackgroundTaskMode()) {
2630 // We should never get to this point in background task mode.
2632 "Could not determine any profile running in backgroundtask mode!\n");
2633 return NS_ERROR_ABORT
;
2635 # endif // MOZ_BACKGROUNDTASKS
2639 ScopedXPCOMStartup xpcom
;
2640 rv
= xpcom
.Initialize();
2641 NS_ENSURE_SUCCESS(rv
, rv
);
2643 rv
= xpcom
.SetWindowCreator(aNative
);
2644 NS_ENSURE_SUCCESS(rv
, NS_ERROR_FAILURE
);
2646 { // extra scoping is needed so we release these components before xpcom
2648 nsCOMPtr
<nsIStringBundleService
> sbs
=
2649 mozilla::components::StringBundle::Service();
2650 NS_ENSURE_TRUE(sbs
, NS_ERROR_FAILURE
);
2652 nsCOMPtr
<nsIStringBundle
> sb
;
2653 sbs
->CreateBundle(kProfileProperties
, getter_AddRefs(sb
));
2654 NS_ENSURE_TRUE_LOG(sbs
, NS_ERROR_FAILURE
);
2656 NS_ConvertUTF8toUTF16
appName(gAppData
->name
);
2657 AutoTArray
<nsString
, 2> params
= {appName
, appName
};
2660 nsAutoString missingMessage
;
2661 rv
= sb
->FormatStringFromName("profileMissing", params
, missingMessage
);
2662 NS_ENSURE_SUCCESS(rv
, NS_ERROR_ABORT
);
2664 nsAutoString missingTitle
;
2665 params
.SetLength(1);
2666 rv
= sb
->FormatStringFromName("profileMissingTitle", params
, missingTitle
);
2667 NS_ENSURE_SUCCESS(rv
, NS_ERROR_ABORT
);
2669 nsCOMPtr
<nsIPromptService
> ps(do_GetService(NS_PROMPTSERVICE_CONTRACTID
));
2670 NS_ENSURE_TRUE(ps
, NS_ERROR_FAILURE
);
2672 ps
->Alert(nullptr, missingTitle
.get(), missingMessage
.get());
2674 return NS_ERROR_ABORT
;
2676 #endif // MOZ_WIDGET_ANDROID
2679 static ReturnAbortOnError
ProfileLockedDialog(nsIFile
* aProfileDir
,
2680 nsIFile
* aProfileLocalDir
,
2681 nsIProfileUnlocker
* aUnlocker
,
2682 nsINativeAppSupport
* aNative
,
2683 nsIProfileLock
** aResult
) {
2687 aProfileDir
->Exists(&exists
);
2689 return ProfileMissingDialog(aNative
);
2692 ScopedXPCOMStartup xpcom
;
2693 rv
= xpcom
.Initialize();
2694 NS_ENSURE_SUCCESS(rv
, rv
);
2696 #if defined(MOZ_TELEMETRY_REPORTING)
2697 // We cannot check if telemetry has been disabled by the user, yet.
2698 // So, rely on the build time settings, instead.
2699 mozilla::Telemetry::WriteFailedProfileLock(aProfileDir
);
2702 rv
= xpcom
.SetWindowCreator(aNative
);
2703 NS_ENSURE_SUCCESS(rv
, NS_ERROR_FAILURE
);
2705 { // extra scoping is needed so we release these components before xpcom
2707 nsCOMPtr
<nsIStringBundleService
> sbs
=
2708 mozilla::components::StringBundle::Service();
2709 NS_ENSURE_TRUE(sbs
, NS_ERROR_FAILURE
);
2711 nsCOMPtr
<nsIStringBundle
> sb
;
2712 sbs
->CreateBundle(kProfileProperties
, getter_AddRefs(sb
));
2713 NS_ENSURE_TRUE_LOG(sbs
, NS_ERROR_FAILURE
);
2715 NS_ConvertUTF8toUTF16
appName(gAppData
->name
);
2716 AutoTArray
<nsString
, 3> params
= {appName
, appName
, appName
};
2718 nsAutoString killMessage
;
2720 rv
= sb
->FormatStringFromName(
2721 aUnlocker
? "restartMessageUnlocker" : "restartMessageNoUnlocker2",
2722 params
, killMessage
);
2724 rv
= sb
->FormatStringFromName(
2725 aUnlocker
? "restartMessageUnlockerMac" : "restartMessageNoUnlockerMac",
2726 params
, killMessage
);
2728 NS_ENSURE_SUCCESS(rv
, NS_ERROR_FAILURE
);
2730 params
.SetLength(1);
2731 nsAutoString killTitle
;
2732 rv
= sb
->FormatStringFromName("restartTitle", params
, killTitle
);
2733 NS_ENSURE_SUCCESS(rv
, NS_ERROR_FAILURE
);
2735 #ifdef MOZ_BACKGROUNDTASKS
2736 if (BackgroundTasks::IsBackgroundTaskMode()) {
2737 // This error is handled specially to exit with a non-zero exit code.
2738 printf_stderr("%s\n", NS_LossyConvertUTF16toASCII(killMessage
).get());
2739 return NS_ERROR_UNEXPECTED
;
2743 if (gfxPlatform::IsHeadless()) {
2744 // TODO: make a way to turn off all dialogs when headless.
2745 Output(true, "%s\n", NS_LossyConvertUTF16toASCII(killMessage
).get());
2746 return NS_ERROR_FAILURE
;
2749 nsCOMPtr
<nsIPromptService
> ps(do_GetService(NS_PROMPTSERVICE_CONTRACTID
));
2750 NS_ENSURE_TRUE(ps
, NS_ERROR_FAILURE
);
2754 #ifdef MOZ_WIDGET_ANDROID
2755 // On Android we always kill the process if the lock is still being held
2758 const uint32_t flags
= (nsIPromptService::BUTTON_TITLE_IS_STRING
*
2759 nsIPromptService::BUTTON_POS_0
) +
2760 (nsIPromptService::BUTTON_TITLE_CANCEL
*
2761 nsIPromptService::BUTTON_POS_1
);
2763 bool checkState
= false;
2764 rv
= ps
->ConfirmEx(nullptr, killTitle
.get(), killMessage
.get(), flags
,
2765 killTitle
.get(), nullptr, nullptr, nullptr,
2766 &checkState
, &button
);
2767 NS_ENSURE_SUCCESS_LOG(rv
, rv
);
2771 rv
= aUnlocker
->Unlock(nsIProfileUnlocker::FORCE_QUIT
);
2772 if (NS_FAILED(rv
)) {
2776 SaveFileToEnv("XRE_PROFILE_PATH", aProfileDir
);
2777 SaveFileToEnv("XRE_PROFILE_LOCAL_PATH", aProfileLocalDir
);
2779 #if defined(MOZ_HAS_REMOTE)
2780 if (gRemoteService
) {
2781 gRemoteService
->UnlockStartup();
2784 return LaunchChild(false, true);
2787 rv
= ps
->Alert(nullptr, killTitle
.get(), killMessage
.get());
2788 NS_ENSURE_SUCCESS_LOG(rv
, rv
);
2791 return NS_ERROR_ABORT
;
2795 static ReturnAbortOnError
ShowProfileDialog(
2796 nsIToolkitProfileService
* aProfileSvc
, nsINativeAppSupport
* aNative
,
2797 const char* aDialogURL
, const char* aTelemetryEnvVar
) {
2800 nsCOMPtr
<nsIFile
> profD
, profLD
;
2801 bool offline
= false;
2802 int32_t dialogReturn
;
2805 ScopedXPCOMStartup xpcom
;
2806 rv
= xpcom
.Initialize();
2807 NS_ENSURE_SUCCESS(rv
, rv
);
2809 rv
= xpcom
.SetWindowCreator(aNative
);
2810 NS_ENSURE_SUCCESS(rv
, NS_ERROR_FAILURE
);
2814 CommandLineServiceMac::SetupMacCommandLine(gRestartArgc
, gRestartArgv
,
2818 { // extra scoping is needed so we release these components before xpcom
2820 nsCOMPtr
<nsIWindowWatcher
> windowWatcher(
2821 do_GetService(NS_WINDOWWATCHER_CONTRACTID
));
2822 nsCOMPtr
<nsIDialogParamBlock
> ioParamBlock(
2823 do_CreateInstance(NS_DIALOGPARAMBLOCK_CONTRACTID
));
2824 nsCOMPtr
<nsIMutableArray
> dlgArray(
2825 do_CreateInstance(NS_ARRAY_CONTRACTID
));
2826 NS_ENSURE_TRUE(windowWatcher
&& ioParamBlock
&& dlgArray
,
2829 ioParamBlock
->SetObjects(dlgArray
);
2831 nsCOMPtr
<nsIAppStartup
> appStartup(components::AppStartup::Service());
2832 NS_ENSURE_TRUE(appStartup
, NS_ERROR_FAILURE
);
2834 nsAutoCString
features("centerscreen,chrome,modal,titlebar");
2835 // If we're launching a private browsing window make sure to set that
2836 // feature for the Profile Manager window as well, so it groups correctly
2837 // on the Windows taskbar.
2838 if (CheckArgExists("private-window") == ARG_FOUND
) {
2839 features
.AppendLiteral(",private");
2841 nsCOMPtr
<mozIDOMWindowProxy
> newWindow
;
2842 rv
= windowWatcher
->OpenWindow(nullptr, nsDependentCString(aDialogURL
),
2843 "_blank"_ns
, features
, ioParamBlock
,
2844 getter_AddRefs(newWindow
));
2846 NS_ENSURE_SUCCESS_LOG(rv
, rv
);
2848 rv
= ioParamBlock
->GetInt(0, &dialogReturn
);
2849 if (NS_FAILED(rv
) || dialogReturn
== nsIToolkitProfileService::exit
) {
2850 return NS_ERROR_ABORT
;
2853 int32_t startOffline
;
2854 rv
= ioParamBlock
->GetInt(1, &startOffline
);
2855 offline
= NS_SUCCEEDED(rv
) && startOffline
== 1;
2857 rv
= dlgArray
->QueryElementAt(0, NS_GET_IID(nsIFile
),
2858 getter_AddRefs(profD
));
2859 NS_ENSURE_SUCCESS_LOG(rv
, rv
);
2861 rv
= dlgArray
->QueryElementAt(1, NS_GET_IID(nsIFile
),
2862 getter_AddRefs(profLD
));
2863 NS_ENSURE_SUCCESS_LOG(rv
, rv
);
2868 SaveToEnv("XRE_START_OFFLINE=1");
2871 // User requested that we restart back into the profile manager.
2872 if (dialogReturn
== nsIToolkitProfileService::restart
) {
2873 SaveToEnv("XRE_RESTART_TO_PROFILE_MANAGER=1");
2875 MOZ_ASSERT(dialogReturn
== nsIToolkitProfileService::launchWithProfile
);
2876 SaveFileToEnv("XRE_PROFILE_PATH", profD
);
2877 SaveFileToEnv("XRE_PROFILE_LOCAL_PATH", profLD
);
2879 SaveToEnv(aTelemetryEnvVar
);
2881 if (gRestartedByOS
) {
2882 // Re-add this argument when actually starting the application.
2884 (char**)realloc(gRestartArgv
, sizeof(char*) * (gRestartArgc
+ 2));
2885 NS_ENSURE_TRUE(newArgv
, NS_ERROR_OUT_OF_MEMORY
);
2886 gRestartArgv
= newArgv
;
2887 gRestartArgv
[gRestartArgc
++] = const_cast<char*>("-os-restarted");
2888 gRestartArgv
[gRestartArgc
] = nullptr;
2890 #if defined(MOZ_HAS_REMOTE)
2891 if (gRemoteService
) {
2892 gRemoteService
->UnlockStartup();
2895 return LaunchChild(false, true);
2898 static ReturnAbortOnError
ShowProfileManager(
2899 nsIToolkitProfileService
* aProfileSvc
, nsINativeAppSupport
* aNative
) {
2900 static const char kProfileManagerURL
[] =
2901 "chrome://mozapps/content/profile/profileSelection.xhtml";
2902 static const char kTelemetryEnv
[] = "XRE_RESTARTED_BY_PROFILE_MANAGER=1";
2904 return ShowProfileDialog(aProfileSvc
, aNative
, kProfileManagerURL
,
2908 static ReturnAbortOnError
ShowProfileSelector(
2909 nsIToolkitProfileService
* aProfileSvc
, nsINativeAppSupport
* aNative
) {
2910 static const char kProfileSelectorURL
[] = "about:profilemanager";
2911 static const char kTelemetryEnv
[] = "XRE_RESTARTED_BY_PROFILE_SELECTOR=1";
2913 return ShowProfileDialog(aProfileSvc
, aNative
, kProfileSelectorURL
,
2917 static bool gDoMigration
= false;
2918 static bool gDoProfileReset
= false;
2919 static nsCOMPtr
<nsIToolkitProfile
> gResetOldProfile
;
2921 static nsresult
LockProfile(nsINativeAppSupport
* aNative
, nsIFile
* aRootDir
,
2922 nsIFile
* aLocalDir
, nsIToolkitProfile
* aProfile
,
2923 nsIProfileLock
** aResult
) {
2924 // If you close Firefox and very quickly reopen it, the old Firefox may
2925 // still be closing down. Rather than immediately showing the
2926 // "Firefox is running but is not responding" message, we spend a few
2927 // seconds retrying first.
2929 static const int kLockRetrySeconds
= 5;
2930 static const int kLockRetrySleepMS
= 100;
2933 nsCOMPtr
<nsIProfileUnlocker
> unlocker
;
2934 const TimeStamp start
= TimeStamp::Now();
2937 rv
= aProfile
->Lock(getter_AddRefs(unlocker
), aResult
);
2939 rv
= NS_LockProfilePath(aRootDir
, aLocalDir
, getter_AddRefs(unlocker
),
2942 if (NS_SUCCEEDED(rv
)) {
2943 StartupTimeline::Record(StartupTimeline::AFTER_PROFILE_LOCKED
);
2946 PR_Sleep(kLockRetrySleepMS
);
2947 } while (TimeStamp::Now() - start
<
2948 TimeDuration::FromSeconds(kLockRetrySeconds
));
2950 return ProfileLockedDialog(aRootDir
, aLocalDir
, unlocker
, aNative
, aResult
);
2953 // Pick a profile. We need to end up with a profile root dir, local dir and
2954 // potentially an nsIToolkitProfile instance.
2956 // 1) check for --profile <path>
2957 // 2) check for -P <name>
2958 // 3) check for --ProfileManager
2959 // 4) use the default profile, if there is one
2960 // 5) if there are *no* profiles, set up profile-migration
2961 // 6) display the profile-manager UI
2962 static nsresult
SelectProfile(nsToolkitProfileService
* aProfileSvc
,
2963 nsINativeAppSupport
* aNative
, nsIFile
** aRootDir
,
2964 nsIFile
** aLocalDir
, nsIToolkitProfile
** aProfile
,
2965 bool* aWasDefaultSelection
) {
2966 StartupTimeline::Record(StartupTimeline::SELECT_PROFILE
);
2970 if (EnvHasValue("MOZ_RESET_PROFILE_RESTART")) {
2971 gDoProfileReset
= true;
2972 gDoMigration
= true;
2975 // reset-profile and migration args need to be checked before any profiles are
2977 ArgResult ar
= CheckArg("reset-profile");
2978 if (ar
== ARG_FOUND
) {
2979 gDoProfileReset
= true;
2982 ar
= CheckArg("migration");
2983 if (ar
== ARG_FOUND
) {
2984 gDoMigration
= true;
2988 // This arg is only used to indicate to telemetry that a profile refresh
2989 // (reset+migration) was requested from the uninstaller, pass this along
2990 // via an environment variable for simplicity.
2991 ar
= CheckArg("uninstaller-profile-refresh");
2992 if (ar
== ARG_FOUND
) {
2993 SaveToEnv("MOZ_UNINSTALLER_PROFILE_REFRESH=1");
2997 if (EnvHasValue("XRE_RESTART_TO_PROFILE_MANAGER")) {
2998 return ShowProfileManager(aProfileSvc
, aNative
);
3001 // Ask the profile manager to select the profile directories to use.
3002 bool didCreate
= false;
3003 rv
= aProfileSvc
->SelectStartupProfile(&gArgc
, gArgv
, gDoProfileReset
,
3004 aRootDir
, aLocalDir
, aProfile
,
3005 &didCreate
, aWasDefaultSelection
);
3007 if (rv
== NS_ERROR_SHOW_PROFILE_MANAGER
) {
3008 return ShowProfileManager(aProfileSvc
, aNative
);
3011 NS_ENSURE_SUCCESS(rv
, rv
);
3014 // For a fresh install, we would like to let users decide
3015 // to do profile migration on their own later after using.
3016 gDoProfileReset
= false;
3017 gDoMigration
= false;
3020 if (gDoProfileReset
&& !*aProfile
) {
3021 NS_WARNING("Profile reset is only supported for named profiles.");
3022 return NS_ERROR_ABORT
;
3025 // No profile could be found. This generally shouldn't happen, a new profile
3026 // should be created in all cases except for profile reset which is covered
3027 // above, but just in case...
3029 NS_WARNING("Failed to select or create profile.");
3030 return NS_ERROR_ABORT
;
3036 #ifdef MOZ_BLOCK_PROFILE_DOWNGRADE
3037 struct FileWriteFunc final
: public JSONWriteFunc
{
3039 explicit FileWriteFunc(FILE* aFile
) : mFile(aFile
) {}
3041 void Write(const Span
<const char>& aStr
) final
{
3042 fprintf(mFile
, "%.*s", int(aStr
.size()), aStr
.data());
3046 static void SubmitDowngradeTelemetry(const nsCString
& aLastVersion
,
3047 bool aHasSync
, int32_t aButton
) {
3048 nsCOMPtr
<nsIPrefService
> prefSvc
=
3049 do_GetService("@mozilla.org/preferences-service;1");
3050 NS_ENSURE_TRUE_VOID(prefSvc
);
3052 nsCOMPtr
<nsIPrefBranch
> prefBranch
= do_QueryInterface(prefSvc
);
3053 NS_ENSURE_TRUE_VOID(prefBranch
);
3057 prefBranch
->GetBoolPref(kPrefHealthReportUploadEnabled
, &enabled
);
3058 NS_ENSURE_SUCCESS_VOID(rv
);
3064 rv
= prefBranch
->GetCharPref("toolkit.telemetry.server", server
);
3065 NS_ENSURE_SUCCESS_VOID(rv
);
3068 rv
= prefBranch
->GetCharPref("toolkit.telemetry.cachedClientID", clientId
);
3069 NS_ENSURE_SUCCESS_VOID(rv
);
3071 nsCString profileGroupId
;
3072 rv
= prefBranch
->GetCharPref("toolkit.telemetry.cachedProfileGroupID",
3074 NS_ENSURE_SUCCESS_VOID(rv
);
3076 rv
= prefSvc
->GetDefaultBranch(nullptr, getter_AddRefs(prefBranch
));
3077 NS_ENSURE_SUCCESS_VOID(rv
);
3079 nsCString
channel("default");
3080 rv
= prefBranch
->GetCharPref("app.update.channel", channel
);
3081 NS_ENSURE_SUCCESS_VOID(rv
);
3084 rv
= nsID::GenerateUUIDInPlace(uuid
);
3085 NS_ENSURE_SUCCESS_VOID(rv
);
3087 nsCString
arch("null");
3088 nsCOMPtr
<nsIPropertyBag2
> sysInfo
=
3089 do_GetService("@mozilla.org/system-info;1");
3090 NS_ENSURE_TRUE_VOID(sysInfo
);
3091 sysInfo
->GetPropertyAsACString(u
"arch"_ns
, arch
);
3095 char date
[sizeof "YYYY-MM-DDThh:mm:ss.000Z"];
3096 strftime(date
, sizeof date
, "%FT%T.000Z", gmtime(&now
));
3098 NSID_TrimBracketsASCII
pingId(uuid
);
3099 constexpr auto pingType
= "downgrade"_ns
;
3101 int32_t pos
= aLastVersion
.Find("_");
3102 if (pos
== kNotFound
) {
3106 const nsDependentCSubstring lastVersion
= Substring(aLastVersion
, 0, pos
);
3107 const nsDependentCSubstring lastBuildId
=
3108 Substring(aLastVersion
, pos
+ 1, 14);
3110 nsPrintfCString
url("%s/submit/telemetry/%s/%s/%s/%s/%s/%s?v=%d",
3111 server
.get(), PromiseFlatCString(pingId
).get(),
3112 pingType
.get(), (const char*)gAppData
->name
,
3113 (const char*)gAppData
->version
, channel
.get(),
3114 (const char*)gAppData
->buildID
,
3115 TELEMETRY_PING_FORMAT_VERSION
);
3117 nsCOMPtr
<nsIFile
> pingFile
;
3118 rv
= NS_GetSpecialDirectory(XRE_USER_APP_DATA_DIR
, getter_AddRefs(pingFile
));
3119 NS_ENSURE_SUCCESS_VOID(rv
);
3120 rv
= pingFile
->Append(u
"Pending Pings"_ns
);
3121 NS_ENSURE_SUCCESS_VOID(rv
);
3122 rv
= pingFile
->Create(nsIFile::DIRECTORY_TYPE
, 0755);
3123 if (NS_FAILED(rv
) && rv
!= NS_ERROR_FILE_ALREADY_EXISTS
) {
3126 rv
= pingFile
->Append(NS_ConvertUTF8toUTF16(pingId
));
3127 NS_ENSURE_SUCCESS_VOID(rv
);
3129 nsCOMPtr
<nsIFile
> pingSender
;
3130 rv
= NS_GetSpecialDirectory(NS_GRE_BIN_DIR
, getter_AddRefs(pingSender
));
3131 NS_ENSURE_SUCCESS_VOID(rv
);
3133 pingSender
->Append(u
"pingsender.exe"_ns
);
3135 pingSender
->Append(u
"pingsender"_ns
);
3139 rv
= pingSender
->Exists(&exists
);
3140 NS_ENSURE_SUCCESS_VOID(rv
);
3146 rv
= pingFile
->OpenANSIFileDesc("w", &file
);
3147 NS_ENSURE_SUCCESS_VOID(rv
);
3149 JSONWriter
w(MakeUnique
<FileWriteFunc
>(file
));
3152 w
.StringProperty("type",
3153 Span
<const char>(pingType
.Data(), pingType
.Length()));
3154 w
.StringProperty("id", PromiseFlatCString(pingId
));
3155 w
.StringProperty("creationDate", MakeStringSpan(date
));
3156 w
.IntProperty("version", TELEMETRY_PING_FORMAT_VERSION
);
3157 w
.StringProperty("clientId", clientId
);
3158 w
.StringProperty("profileGroupId", profileGroupId
);
3159 w
.StartObjectProperty("application");
3161 w
.StringProperty("architecture", arch
);
3164 MakeStringSpan(static_cast<const char*>(gAppData
->buildID
)));
3166 "name", MakeStringSpan(static_cast<const char*>(gAppData
->name
)));
3169 MakeStringSpan(static_cast<const char*>(gAppData
->version
)));
3170 w
.StringProperty("displayVersion",
3171 MOZ_STRINGIFY(MOZ_APP_VERSION_DISPLAY
));
3173 "vendor", MakeStringSpan(static_cast<const char*>(gAppData
->vendor
)));
3174 w
.StringProperty("platformVersion", gToolkitVersion
);
3175 # ifdef TARGET_XPCOM_ABI
3176 w
.StringProperty("xpcomAbi", TARGET_XPCOM_ABI
);
3178 w
.StringProperty("xpcomAbi", "unknown");
3180 w
.StringProperty("channel", channel
);
3183 w
.StartObjectProperty("payload");
3185 w
.StringProperty("lastVersion", PromiseFlatCString(lastVersion
));
3186 w
.StringProperty("lastBuildId", PromiseFlatCString(lastBuildId
));
3187 w
.BoolProperty("hasSync", aHasSync
);
3188 w
.IntProperty("button", aButton
);
3196 PathString filePath
= pingFile
->NativePath();
3197 const filesystem::Path::value_type
* args
[2];
3199 nsString urlw
= NS_ConvertUTF8toUTF16(url
);
3200 args
[0] = urlw
.get();
3202 args
[0] = url
.get();
3204 args
[1] = filePath
.get();
3206 nsCOMPtr
<nsIProcess
> process
=
3207 do_CreateInstance("@mozilla.org/process/util;1");
3208 NS_ENSURE_TRUE_VOID(process
);
3209 process
->Init(pingSender
);
3210 process
->SetStartHidden(true);
3211 process
->SetNoShell(true);
3214 process
->Runw(false, args
, 2);
3216 process
->Run(false, args
, 2);
3220 static const char kProfileDowngradeURL
[] =
3221 "chrome://mozapps/content/profile/profileDowngrade.xhtml";
3223 static ReturnAbortOnError
CheckDowngrade(nsIFile
* aProfileDir
,
3224 nsINativeAppSupport
* aNative
,
3225 nsIToolkitProfileService
* aProfileSvc
,
3226 const nsCString
& aLastVersion
) {
3231 if (gfxPlatform::IsHeadless()) {
3232 // TODO: make a way to turn off all dialogs when headless.
3234 "This profile was last used with a newer version of this "
3235 "application. Please create a new profile.\n");
3236 return NS_ERROR_ABORT
;
3239 ScopedXPCOMStartup xpcom
;
3240 rv
= xpcom
.Initialize();
3241 NS_ENSURE_SUCCESS(rv
, rv
);
3243 rv
= xpcom
.SetWindowCreator(aNative
);
3244 NS_ENSURE_SUCCESS(rv
, rv
);
3246 { // extra scoping is needed so we release these components before xpcom
3248 bool hasSync
= false;
3249 nsCOMPtr
<nsIPrefService
> prefSvc
=
3250 do_GetService("@mozilla.org/preferences-service;1");
3251 NS_ENSURE_TRUE(prefSvc
, rv
);
3253 nsCOMPtr
<nsIFile
> prefsFile
;
3254 rv
= aProfileDir
->Clone(getter_AddRefs(prefsFile
));
3255 NS_ENSURE_SUCCESS(rv
, rv
);
3257 rv
= prefsFile
->Append(u
"prefs.js"_ns
);
3258 NS_ENSURE_SUCCESS(rv
, rv
);
3260 rv
= prefSvc
->ReadUserPrefsFromFile(prefsFile
);
3261 if (NS_SUCCEEDED(rv
)) {
3262 nsCOMPtr
<nsIPrefBranch
> prefBranch
= do_QueryInterface(prefSvc
);
3264 rv
= prefBranch
->PrefHasUserValue("services.sync.username", &hasSync
);
3265 NS_ENSURE_SUCCESS(rv
, rv
);
3268 nsCOMPtr
<nsIWindowWatcher
> windowWatcher
=
3269 do_GetService(NS_WINDOWWATCHER_CONTRACTID
);
3270 NS_ENSURE_TRUE(windowWatcher
, NS_ERROR_ABORT
);
3272 nsCOMPtr
<nsIAppStartup
> appStartup(components::AppStartup::Service());
3273 NS_ENSURE_TRUE(appStartup
, NS_ERROR_FAILURE
);
3275 nsCOMPtr
<nsIDialogParamBlock
> paramBlock
=
3276 do_CreateInstance(NS_DIALOGPARAMBLOCK_CONTRACTID
);
3277 NS_ENSURE_TRUE(paramBlock
, NS_ERROR_ABORT
);
3281 flags
|= nsIToolkitProfileService::hasSync
;
3284 paramBlock
->SetInt(0, flags
);
3286 nsAutoCString
features("centerscreen,chrome,modal,titlebar");
3287 // If we're launching a private browsing window make sure to set that
3288 // feature for the Profile Manager window as well, so it groups correctly
3289 // on the Windows taskbar.
3290 if (CheckArgExists("private-window") == ARG_FOUND
) {
3291 features
.AppendLiteral(",private");
3293 nsCOMPtr
<mozIDOMWindowProxy
> newWindow
;
3294 rv
= windowWatcher
->OpenWindow(
3295 nullptr, nsDependentCString(kProfileDowngradeURL
), "_blank"_ns
,
3296 features
, paramBlock
, getter_AddRefs(newWindow
));
3297 NS_ENSURE_SUCCESS(rv
, rv
);
3299 paramBlock
->GetInt(1, &result
);
3301 SubmitDowngradeTelemetry(aLastVersion
, hasSync
, result
);
3305 if (result
== nsIToolkitProfileService::createNewProfile
) {
3306 // Create a new profile and start it.
3307 nsCString profileName
;
3308 profileName
.AssignLiteral("default");
3309 # ifdef MOZ_DEDICATED_PROFILES
3310 profileName
.Append("-" MOZ_STRINGIFY(MOZ_UPDATE_CHANNEL
));
3312 nsCOMPtr
<nsIToolkitProfile
> newProfile
;
3313 rv
= aProfileSvc
->CreateUniqueProfile(nullptr, profileName
,
3314 getter_AddRefs(newProfile
));
3315 NS_ENSURE_SUCCESS(rv
, rv
);
3316 rv
= aProfileSvc
->SetDefaultProfile(newProfile
);
3317 NS_ENSURE_SUCCESS(rv
, rv
);
3318 rv
= aProfileSvc
->Flush();
3319 NS_ENSURE_SUCCESS(rv
, rv
);
3321 nsCOMPtr
<nsIFile
> profD
, profLD
;
3322 rv
= newProfile
->GetRootDir(getter_AddRefs(profD
));
3323 NS_ENSURE_SUCCESS(rv
, rv
);
3324 rv
= newProfile
->GetLocalDir(getter_AddRefs(profLD
));
3325 NS_ENSURE_SUCCESS(rv
, rv
);
3327 SaveFileToEnv("XRE_PROFILE_PATH", profD
);
3328 SaveFileToEnv("XRE_PROFILE_LOCAL_PATH", profLD
);
3330 return LaunchChild(false, true);
3334 return NS_ERROR_ABORT
;
3339 * Extracts the various parts of a compatibility version string.
3341 * Compatibility versions are of the form
3342 * "<appversion>_<appbuildid>/<platformbuildid>". The toolkit version comparator
3343 * can only handle 32-bit numbers and in the normal case build IDs are larger
3344 * than this. So if the build ID is numeric we split it into two version parts.
3346 static void ExtractCompatVersionInfo(const nsACString
& aCompatVersion
,
3347 nsACString
& aAppVersion
,
3348 nsACString
& aAppBuildID
) {
3349 int32_t underscorePos
= aCompatVersion
.FindChar('_');
3350 int32_t slashPos
= aCompatVersion
.FindChar('/');
3352 if (underscorePos
== kNotFound
|| slashPos
== kNotFound
||
3353 slashPos
< underscorePos
) {
3355 "compatibility.ini Version string does not match the expected format.");
3357 // Fall back to just using the entire string as the version.
3358 aAppVersion
= aCompatVersion
;
3359 aAppBuildID
.Truncate(0);
3363 aAppVersion
= Substring(aCompatVersion
, 0, underscorePos
);
3364 aAppBuildID
= Substring(aCompatVersion
, underscorePos
+ 1,
3365 slashPos
- (underscorePos
+ 1));
3369 * Compares the provided compatibility versions. Returns 0 if they match,
3370 * < 0 if the new version is considered an upgrade from the old version and
3371 * > 0 if the new version is considered a downgrade from the old version.
3373 int32_t CompareCompatVersions(const nsACString
& aOldCompatVersion
,
3374 const nsACString
& aNewCompatVersion
) {
3375 // Hardcode the case where the last run was in safe mode (Bug 1556612). We
3376 // cannot tell if this is a downgrade or not so just assume it isn't and let
3377 // the user proceed.
3378 if (aOldCompatVersion
.EqualsLiteral("Safe Mode")) {
3382 // Extract the major version part from the version string and only use that
3383 // for version comparison.
3384 int32_t index
= aOldCompatVersion
.FindChar('.');
3385 const nsACString
& oldMajorVersion
= Substring(
3386 aOldCompatVersion
, 0, index
< 0 ? aOldCompatVersion
.Length() : index
);
3387 index
= aNewCompatVersion
.FindChar('.');
3388 const nsACString
& newMajorVersion
= Substring(
3389 aNewCompatVersion
, 0, index
< 0 ? aNewCompatVersion
.Length() : index
);
3391 return CompareVersions(PromiseFlatCString(oldMajorVersion
).get(),
3392 PromiseFlatCString(newMajorVersion
).get());
3396 * Checks the compatibility.ini file to see if we have updated our application
3397 * or otherwise invalidated our caches. If the application has been updated,
3398 * we return false; otherwise, we return true.
3400 * We also write the status of the caches (valid/invalid) into the return param
3401 * aCachesOK. The aCachesOK is always invalid if the application has been
3404 * Finally, aIsDowngrade is set to true if the current application is older
3405 * than that previously used by the profile.
3407 static bool CheckCompatibility(nsIFile
* aProfileDir
, const nsCString
& aVersion
,
3408 const nsCString
& aOSABI
, nsIFile
* aXULRunnerDir
,
3409 nsIFile
* aAppDir
, nsIFile
* aFlagFile
,
3410 bool* aCachesOK
, bool* aIsDowngrade
,
3411 nsCString
& aLastVersion
) {
3413 *aIsDowngrade
= false;
3414 gLastAppVersion
.SetIsVoid(true);
3415 gLastAppBuildID
.SetIsVoid(true);
3417 nsCOMPtr
<nsIFile
> file
;
3418 aProfileDir
->Clone(getter_AddRefs(file
));
3419 if (!file
) return false;
3420 file
->AppendNative(FILE_COMPATIBILITY_INFO
);
3423 nsresult rv
= parser
.Init(file
);
3424 if (NS_FAILED(rv
)) return false;
3426 rv
= parser
.GetString("Compatibility", "LastVersion", aLastVersion
);
3427 if (NS_FAILED(rv
)) {
3431 if (!aLastVersion
.Equals(aVersion
)) {
3432 // The version is not the same. Whether it's a downgrade depends on an
3433 // actual comparison:
3434 *aIsDowngrade
= 0 < CompareCompatVersions(aLastVersion
, aVersion
);
3435 ExtractCompatVersionInfo(aLastVersion
, gLastAppVersion
, gLastAppBuildID
);
3439 // If we get here, the version matched, but there may still be other
3440 // differences between us and the build that the profile last ran under.
3442 gLastAppVersion
.Assign(gAppData
->version
);
3443 gLastAppBuildID
.Assign(gAppData
->buildID
);
3446 rv
= parser
.GetString("Compatibility", "LastOSABI", buf
);
3447 if (NS_FAILED(rv
) || !aOSABI
.Equals(buf
)) return false;
3449 rv
= parser
.GetString("Compatibility", "LastPlatformDir", buf
);
3450 if (NS_FAILED(rv
)) return false;
3452 nsCOMPtr
<nsIFile
> lf
;
3453 rv
= NS_NewNativeLocalFile(""_ns
, false, getter_AddRefs(lf
));
3454 if (NS_FAILED(rv
)) return false;
3456 rv
= lf
->SetPersistentDescriptor(buf
);
3457 if (NS_FAILED(rv
)) return false;
3460 rv
= lf
->Equals(aXULRunnerDir
, &eq
);
3461 if (NS_FAILED(rv
) || !eq
) return false;
3464 rv
= parser
.GetString("Compatibility", "LastAppDir", buf
);
3465 if (NS_FAILED(rv
)) return false;
3467 rv
= NS_NewNativeLocalFile(""_ns
, false, getter_AddRefs(lf
));
3468 if (NS_FAILED(rv
)) return false;
3470 rv
= lf
->SetPersistentDescriptor(buf
);
3471 if (NS_FAILED(rv
)) return false;
3473 rv
= lf
->Equals(aAppDir
, &eq
);
3474 if (NS_FAILED(rv
) || !eq
) return false;
3477 // If we see this flag, caches are invalid.
3478 rv
= parser
.GetString("Compatibility", "InvalidateCaches", buf
);
3479 *aCachesOK
= (NS_FAILED(rv
) || !buf
.EqualsLiteral("1"));
3481 bool purgeCaches
= false;
3482 if (aFlagFile
&& NS_SUCCEEDED(aFlagFile
->Exists(&purgeCaches
)) &&
3490 void BuildCompatVersion(const char* aAppVersion
, const char* aAppBuildID
,
3491 const char* aToolkitBuildID
, nsACString
& aBuf
) {
3492 aBuf
.Assign(aAppVersion
);
3494 aBuf
.Append(aAppBuildID
);
3496 aBuf
.Append(aToolkitBuildID
);
3499 static void BuildVersion(nsCString
& aBuf
) {
3500 BuildCompatVersion(gAppData
->version
, gAppData
->buildID
, gToolkitBuildID
,
3504 static void WriteVersion(nsIFile
* aProfileDir
, const nsCString
& aVersion
,
3505 const nsCString
& aOSABI
, nsIFile
* aXULRunnerDir
,
3506 nsIFile
* aAppDir
, bool invalidateCache
) {
3507 nsCOMPtr
<nsIFile
> file
;
3508 aProfileDir
->Clone(getter_AddRefs(file
));
3510 file
->AppendNative(FILE_COMPATIBILITY_INFO
);
3512 nsAutoCString platformDir
;
3513 Unused
<< aXULRunnerDir
->GetPersistentDescriptor(platformDir
);
3515 nsAutoCString appDir
;
3516 if (aAppDir
) Unused
<< aAppDir
->GetPersistentDescriptor(appDir
);
3519 nsresult rv
= file
->OpenNSPRFileDesc(PR_WRONLY
| PR_CREATE_FILE
| PR_TRUNCATE
,
3521 if (NS_FAILED(rv
)) {
3522 NS_ERROR("could not create output stream");
3526 static const char kHeader
[] = "[Compatibility]" NS_LINEBREAK
"LastVersion=";
3528 PR_Write(fd
, kHeader
, sizeof(kHeader
) - 1);
3529 PR_Write(fd
, aVersion
.get(), aVersion
.Length());
3531 static const char kOSABIHeader
[] = NS_LINEBREAK
"LastOSABI=";
3532 PR_Write(fd
, kOSABIHeader
, sizeof(kOSABIHeader
) - 1);
3533 PR_Write(fd
, aOSABI
.get(), aOSABI
.Length());
3535 static const char kPlatformDirHeader
[] = NS_LINEBREAK
"LastPlatformDir=";
3537 PR_Write(fd
, kPlatformDirHeader
, sizeof(kPlatformDirHeader
) - 1);
3538 PR_Write(fd
, platformDir
.get(), platformDir
.Length());
3540 static const char kAppDirHeader
[] = NS_LINEBREAK
"LastAppDir=";
3542 PR_Write(fd
, kAppDirHeader
, sizeof(kAppDirHeader
) - 1);
3543 PR_Write(fd
, appDir
.get(), appDir
.Length());
3546 static const char kInvalidationHeader
[] = NS_LINEBREAK
"InvalidateCaches=1";
3547 if (invalidateCache
)
3548 PR_Write(fd
, kInvalidationHeader
, sizeof(kInvalidationHeader
) - 1);
3550 static const char kNL
[] = NS_LINEBREAK
;
3551 PR_Write(fd
, kNL
, sizeof(kNL
) - 1);
3557 * Returns true if the startup cache file was successfully removed.
3558 * Returns false if file->Clone fails at any point (OOM) or if unable
3559 * to remove the startup cache file. Note in particular the return value
3560 * is unaffected by a failure to remove extensions.ini
3562 static bool RemoveComponentRegistries(nsIFile
* aProfileDir
,
3563 nsIFile
* aLocalProfileDir
,
3564 bool aRemoveEMFiles
) {
3565 nsCOMPtr
<nsIFile
> file
;
3566 aProfileDir
->Clone(getter_AddRefs(file
));
3567 if (!file
) return false;
3569 if (aRemoveEMFiles
) {
3570 file
->SetNativeLeafName("extensions.ini"_ns
);
3571 file
->Remove(false);
3574 aLocalProfileDir
->Clone(getter_AddRefs(file
));
3575 if (!file
) return false;
3577 file
->AppendNative("startupCache"_ns
);
3578 nsresult rv
= file
->Remove(true);
3579 return NS_SUCCEEDED(rv
) || rv
== NS_ERROR_FILE_NOT_FOUND
;
3582 // When we first initialize the crash reporter we don't have a profile,
3583 // so we set the minidump path to $TEMP. Once we have a profile,
3584 // we set it to $PROFILE/minidumps, creating the directory
3586 static void MakeOrSetMinidumpPath(nsIFile
* profD
) {
3587 nsCOMPtr
<nsIFile
> dumpD
;
3588 profD
->Clone(getter_AddRefs(dumpD
));
3592 // XXX: do some more error checking here
3593 dumpD
->Append(u
"minidumps"_ns
);
3594 dumpD
->Exists(&fileExists
);
3596 nsresult rv
= dumpD
->Create(nsIFile::DIRECTORY_TYPE
, 0700);
3597 NS_ENSURE_SUCCESS_VOID(rv
);
3600 nsAutoString pathStr
;
3601 if (NS_SUCCEEDED(dumpD
->GetPath(pathStr
)))
3602 CrashReporter::SetMinidumpPath(pathStr
);
3606 const XREAppData
* gAppData
= nullptr;
3609 * NSPR will search for the "nspr_use_zone_allocator" symbol throughout
3610 * the process and use it to determine whether the application defines its own
3611 * memory allocator or not.
3613 * Since most applications (e.g. Firefox and Thunderbird) don't use any special
3614 * allocators and therefore don't define this symbol, NSPR must search the
3615 * entire process, which reduces startup performance.
3617 * By defining the symbol here, we can avoid the wasted lookup and hopefully
3618 * improve startup performance.
3620 NS_VISIBILITY_DEFAULT PRBool nspr_use_zone_allocator
= PR_FALSE
;
3622 #ifdef CAIRO_HAS_DWRITE_FONT
3624 # include <dwrite.h>
3625 # include "nsWindowsHelpers.h"
3627 # ifdef DEBUG_DWRITE_STARTUP
3629 # define LOGREGISTRY(msg) LogRegistryEvent(msg)
3631 // for use when monitoring process
3632 static void LogRegistryEvent(const wchar_t* msg
) {
3637 wsprintf(buf
, L
" log %s", msg
);
3638 hr
= RegOpenKeyEx(HKEY_LOCAL_MACHINE
, buf
, 0, KEY_READ
, &dummyKey
);
3639 if (SUCCEEDED(hr
)) {
3640 RegCloseKey(dummyKey
);
3645 # define LOGREGISTRY(msg)
3649 static DWORD WINAPI
InitDwriteBG(LPVOID lpdwThreadParam
) {
3650 SetThreadPriority(GetCurrentThread(), THREAD_MODE_BACKGROUND_BEGIN
);
3651 LOGREGISTRY(L
"loading dwrite.dll");
3652 HMODULE dwdll
= LoadLibrarySystem32(L
"dwrite.dll");
3654 decltype(DWriteCreateFactory
)* createDWriteFactory
=
3655 (decltype(DWriteCreateFactory
)*)GetProcAddress(dwdll
,
3656 "DWriteCreateFactory");
3657 if (createDWriteFactory
) {
3658 LOGREGISTRY(L
"creating dwrite factory");
3659 IDWriteFactory
* factory
;
3660 HRESULT hr
= createDWriteFactory(DWRITE_FACTORY_TYPE_SHARED
,
3661 __uuidof(IDWriteFactory
),
3662 reinterpret_cast<IUnknown
**>(&factory
));
3663 if (SUCCEEDED(hr
)) {
3664 LOGREGISTRY(L
"dwrite factory done");
3666 LOGREGISTRY(L
"freed factory");
3668 LOGREGISTRY(L
"failed to create factory");
3672 SetThreadPriority(GetCurrentThread(), THREAD_MODE_BACKGROUND_END
);
3677 #include "GeckoProfiler.h"
3678 #include "ProfilerControl.h"
3680 // Encapsulates startup and shutdown state for XRE_main
3683 XREMain() = default;
3686 mScopedXPCOM
= nullptr;
3690 int XRE_main(int argc
, char* argv
[], const BootstrapConfig
& aConfig
);
3691 int XRE_mainInit(bool* aExitFlag
);
3692 int XRE_mainStartup(bool* aExitFlag
);
3693 nsresult
XRE_mainRun();
3695 bool CheckLastStartupWasCrash();
3697 nsCOMPtr
<nsINativeAppSupport
> mNativeApp
;
3698 RefPtr
<nsToolkitProfileService
> mProfileSvc
;
3699 nsCOMPtr
<nsIFile
> mProfD
;
3700 nsCOMPtr
<nsIFile
> mProfLD
;
3701 nsCOMPtr
<nsIProfileLock
> mProfileLock
;
3703 UniquePtr
<ScopedXPCOMStartup
> mScopedXPCOM
;
3704 UniquePtr
<XREAppData
> mAppData
;
3706 nsXREDirProvider mDirProvider
;
3708 #ifdef MOZ_WIDGET_GTK
3709 nsAutoCString mXDGActivationToken
;
3710 nsAutoCString mDesktopStartupID
;
3713 bool mStartOffline
= false;
3714 nsAutoCString mOriginToForceQUIC
;
3715 #if defined(MOZ_HAS_REMOTE)
3716 bool mDisableRemoteClient
= false;
3720 #if defined(XP_UNIX) && !defined(ANDROID)
3721 static SmprintfPointer
FormatUid(uid_t aId
) {
3722 if (const auto pw
= getpwuid(aId
)) {
3723 return mozilla::Smprintf("%s", pw
->pw_name
);
3725 return mozilla::Smprintf("uid %d", static_cast<int>(aId
));
3728 // Bug 1323302: refuse to run under sudo or similar.
3729 static bool CheckForUserMismatch() {
3730 static char const* const kVars
[] = {
3732 # ifdef MOZ_WIDGET_GTK
3740 const uid_t euid
= geteuid();
3742 // On Linux it's possible to have superuser capabilities with a
3743 // nonzero uid, but anyone who knows enough to make that happen
3744 // probably knows enough to debug the resulting problems.
3745 // Otherwise, a non-root user can't cause the problems we're
3750 for (const auto var
: kVars
) {
3751 if (const auto path
= PR_GetEnv(var
)) {
3753 if (stat(path
, &st
) == 0) {
3754 if (st
.st_uid
!= euid
) {
3755 const auto owner
= FormatUid(st
.st_uid
);
3757 "Running " MOZ_APP_DISPLAYNAME
3758 " as root in a regular"
3759 " user's session is not supported. ($%s is %s which is"
3761 var
, path
, owner
.get());
3769 #else // !XP_UNIX || ANDROID
3770 static bool CheckForUserMismatch() { return false; }
3773 void mozilla::startup::IncreaseDescriptorLimits() {
3775 // Increase the fd limit to accomodate IPC resources like shared memory.
3777 // We use Mach IPC for shared memory, so a lower limit suffices.
3778 // See also the Darwin case in config/external/nspr/pr/moz.build
3779 static constexpr rlim_t kFDs
= 4096;
3780 # else // Unix but not Darwin
3781 // This can be increased if needed, but also be aware that Linux
3782 // distributions may impose hard limits less than this.
3783 static constexpr rlim_t kFDs
= 65536;
3784 # endif // Darwin or not
3787 if (getrlimit(RLIMIT_NOFILE
, &rlim
) != 0) {
3788 Output(false, "getrlimit: %s\n", strerror(errno
));
3791 // Don't decrease the limit if it's already high enough, but don't
3792 // try to go over the hard limit. (RLIM_INFINITY isn't required to
3793 // be the numerically largest rlim_t, so don't assume that.)
3794 if (rlim
.rlim_cur
!= RLIM_INFINITY
&& rlim
.rlim_cur
< kFDs
&&
3795 rlim
.rlim_cur
< rlim
.rlim_max
) {
3796 if (rlim
.rlim_max
!= RLIM_INFINITY
&& rlim
.rlim_max
< kFDs
) {
3797 rlim
.rlim_cur
= rlim
.rlim_max
;
3799 rlim
.rlim_cur
= kFDs
;
3801 if (setrlimit(RLIMIT_NOFILE
, &rlim
) != 0) {
3802 Output(false, "setrlimit: %s\n", strerror(errno
));
3810 static uint32_t GetMicrocodeVersionByVendor(HKEY key
, DWORD upper
,
3812 WCHAR data
[13]; // The CPUID vendor string is 12 characters long plus null
3813 DWORD len
= sizeof(data
);
3816 if (RegQueryValueExW(key
, L
"VendorIdentifier", nullptr, &vtype
,
3817 reinterpret_cast<LPBYTE
>(data
), &len
) == ERROR_SUCCESS
) {
3818 if (wcscmp(L
"GenuineIntel", data
) == 0) {
3819 // Intel reports the microcode version in the upper 32 bits of the MSR
3823 if (wcscmp(L
"AuthenticAMD", data
) == 0) {
3824 // AMD reports the microcode version in the lower 32 bits of the MSR
3828 // Unknown CPU vendor, return whatever half is non-zero
3829 return lower
? lower
: upper
;
3832 return 0; // No clue
3837 static void MaybeAddCPUMicrocodeCrashAnnotation() {
3839 // Add CPU microcode version to the crash report as "CPUMicrocodeVersion".
3840 // It feels like this code may belong in nsSystemInfo instead.
3841 uint32_t cpuUpdateRevision
= 0;
3843 static const WCHAR keyName
[] =
3844 L
"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0";
3846 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, keyName
, 0, KEY_QUERY_VALUE
, &key
) ==
3848 DWORD updateRevision
[2];
3849 DWORD len
= sizeof(updateRevision
);
3852 // Windows 7 uses "Update Signature", 8 uses "Update Revision".
3853 // For AMD CPUs, "CurrentPatchLevel" is sometimes used.
3854 // Take the first one we find.
3855 LPCWSTR choices
[] = {L
"Update Signature", L
"Update Revision",
3856 L
"CurrentPatchLevel"};
3857 for (const auto& oneChoice
: choices
) {
3858 if (RegQueryValueExW(key
, oneChoice
, nullptr, &vtype
,
3859 reinterpret_cast<LPBYTE
>(updateRevision
),
3860 &len
) == ERROR_SUCCESS
) {
3861 if (vtype
== REG_BINARY
&& len
== sizeof(updateRevision
)) {
3862 cpuUpdateRevision
= GetMicrocodeVersionByVendor(
3863 key
, updateRevision
[1], updateRevision
[0]);
3867 if (vtype
== REG_DWORD
&& len
== sizeof(updateRevision
[0])) {
3868 cpuUpdateRevision
= static_cast<int>(updateRevision
[0]);
3875 if (cpuUpdateRevision
> 0) {
3876 CrashReporter::RecordAnnotationNSCString(
3877 CrashReporter::Annotation::CPUMicrocodeVersion
,
3878 nsPrintfCString("0x%" PRIx32
, cpuUpdateRevision
));
3883 #if defined(MOZ_BACKGROUNDTASKS)
3884 static void SetupConsoleForBackgroundTask(
3885 const nsCString
& aBackgroundTaskName
) {
3886 // We do not suppress output on Windows because:
3887 // 1. Background task subprocesses launched via LaunchApp() does not attach to
3889 // 2. Suppressing output intermittently causes failures on when running
3890 // multiple tasks (see bug 1831631)
3892 if (BackgroundTasks::IsNoOutputTaskName(aBackgroundTaskName
) &&
3893 !CheckArg("attach-console") &&
3894 !EnvHasValue("MOZ_BACKGROUNDTASKS_IGNORE_NO_OUTPUT")) {
3895 // Suppress output, somewhat crudely. We need to suppress stderr as well
3896 // as stdout because assertions, of which there are many, write to stderr.
3897 Unused
<< freopen("/dev/null", "w", stdout
);
3898 Unused
<< freopen("/dev/null", "w", stderr
);
3902 printf_stderr("*** You are running in background task mode. ***\n");
3907 * XRE_mainInit - Initial setup and command line parameter processing.
3908 * Main() will exit early if either return value != 0 or if aExitFlag is
3911 int XREMain::XRE_mainInit(bool* aExitFlag
) {
3912 if (!aExitFlag
) return 1;
3915 atexit(UnexpectedExit
);
3916 auto expectedShutdown
= mozilla::MakeScopeExit([&] { MozExpectedExit(); });
3918 StartupTimeline::Record(StartupTimeline::MAIN
);
3920 if (CheckForUserMismatch()) {
3925 mozilla::MacAutoreleasePool pool
;
3930 #ifdef MOZ_BACKGROUNDTASKS
3931 Maybe
<nsCString
> backgroundTask
= Nothing();
3932 const char* backgroundTaskName
= nullptr;
3934 CheckArg("backgroundtask", &backgroundTaskName
, CheckArgFlag::None
)) {
3935 backgroundTask
= Some(backgroundTaskName
);
3937 SetupConsoleForBackgroundTask(backgroundTask
.ref());
3940 BackgroundTasks::Init(backgroundTask
);
3944 if (PR_GetEnv("MOZ_RUN_GTEST")
3946 || PR_GetEnv("FUZZER")
3948 # ifdef MOZ_BACKGROUNDTASKS
3949 || BackgroundTasks::IsBackgroundTaskMode()
3952 // Enable headless mode and assert that it worked, since gfxPlatform
3953 // uses a static bool set after the first call to `IsHeadless`.
3954 // Note: Android gtests seem to require an Activity and fail to start
3955 // with headless mode enabled.
3956 PR_SetEnv("MOZ_HEADLESS=1");
3957 MOZ_ASSERT(gfxPlatform::IsHeadless());
3961 if (PR_GetEnv("MOZ_CHAOSMODE")) {
3962 ChaosFeature feature
= ChaosFeature::Any
;
3963 long featureInt
= strtol(PR_GetEnv("MOZ_CHAOSMODE"), nullptr, 16);
3965 // NOTE: MOZ_CHAOSMODE=0 or a non-hex value maps to Any feature.
3966 feature
= static_cast<ChaosFeature
>(featureInt
);
3968 ChaosMode::SetChaosFeature(feature
);
3971 if (CheckArgExists("fxr")) {
3972 gFxREmbedded
= true;
3975 if (ChaosMode::isActive(ChaosFeature::Any
)) {
3977 "*** You are running in chaos test mode. See ChaosMode.h. ***\n");
3980 if (CheckArg("headless") || CheckArgExists("screenshot")) {
3981 PR_SetEnv("MOZ_HEADLESS=1");
3984 if (gfxPlatform::IsHeadless()) {
3985 #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) || defined(XP_MACOSX)
3986 printf_stderr("*** You are running in headless mode.\n");
3990 "Error: headless mode is not currently supported on this platform.\n");
3995 // To avoid taking focus when running in headless mode immediately
3996 // transition Firefox to a background application.
3997 ProcessSerialNumber psn
= {0, kCurrentProcess
};
3998 OSStatus transformStatus
=
3999 TransformProcessType(&psn
, kProcessTransformToBackgroundApplication
);
4000 if (transformStatus
!= noErr
) {
4001 NS_ERROR("Failed to make process a background application.");
4007 gKioskMode
= CheckArg("kiosk", nullptr, CheckArgFlag::None
);
4008 const char* kioskMonitorNumber
= nullptr;
4009 if (CheckArg("kiosk-monitor", &kioskMonitorNumber
, CheckArgFlag::None
)) {
4011 gKioskMonitor
= atoi(kioskMonitorNumber
);
4014 if (XRE_IsParentProcess()) {
4015 gAllowContentAnalysisArgPresent
=
4016 CheckArg("allow-content-analysis", nullptr, CheckArgFlag::None
) ==
4024 if (PR_GetEnv("XRE_MAIN_BREAK")) NS_BREAK();
4027 mozilla::startup::IncreaseDescriptorLimits();
4029 SetupErrorHandling(gArgv
[0]);
4031 #ifdef CAIRO_HAS_DWRITE_FONT
4033 // Bug 602792 - when DWriteCreateFactory is called the dwrite client dll
4034 // starts the FntCache service if it isn't already running (it's set
4035 // to manual startup by default in Windows 7 RTM). Subsequent DirectWrite
4036 // calls cause the IDWriteFactory object to communicate with the FntCache
4037 // service with a timeout; if there's no response after the timeout, the
4038 // DirectWrite client library will assume the service isn't around and do
4039 // manual font file I/O on _all_ system fonts. To avoid this, load the
4040 // dwrite library and create a factory as early as possible so that the
4041 // FntCache service is ready by the time it's needed.
4043 CreateThread(nullptr, 0, &InitDwriteBG
, nullptr, 0, nullptr);
4048 const char* home
= PR_GetEnv("HOME");
4049 if (!home
|| !*home
) {
4050 struct passwd
* pw
= getpwuid(geteuid());
4051 if (!pw
|| !pw
->pw_dir
) {
4052 Output(true, "Could not determine HOME directory");
4055 SaveWordToEnv("HOME", nsDependentCString(pw
->pw_dir
));
4059 #ifdef MOZ_ACCESSIBILITY_ATK
4060 // Suppress atk-bridge init at startup, until mozilla accessibility is
4061 // initialized. This works after gnome 2.24.2.
4062 SaveToEnv("NO_AT_BRIDGE=1");
4065 // Check for application.ini overrides
4066 const char* override
= nullptr;
4067 ar
= CheckArg("override", &override
);
4068 if (ar
== ARG_BAD
) {
4069 Output(true, "Incorrect number of arguments passed to --override");
4072 if (ar
== ARG_FOUND
) {
4073 nsCOMPtr
<nsIFile
> overrideLF
;
4074 rv
= XRE_GetFileFromPath(override
, getter_AddRefs(overrideLF
));
4075 if (NS_FAILED(rv
)) {
4076 Output(true, "Error: unrecognized override.ini path.\n");
4080 rv
= XRE_ParseAppData(overrideLF
, *mAppData
);
4081 if (NS_FAILED(rv
)) {
4082 Output(true, "Couldn't read override.ini");
4087 // Check sanity and correctness of app data.
4089 if (!mAppData
->name
) {
4090 Output(true, "Error: App:Name not specified in application.ini\n");
4093 if (!mAppData
->buildID
) {
4094 Output(true, "Error: App:BuildID not specified in application.ini\n");
4098 // XXX Originally ScopedLogging was here? Now it's in XRE_main above
4101 if (!mAppData
->minVersion
) {
4102 Output(true, "Error: Gecko:MinVersion not specified in application.ini\n");
4106 if (!mAppData
->maxVersion
) {
4107 // If no maxVersion is specified, we assume the app is only compatible
4108 // with the initial preview release. Do not increment this number ever!
4109 mAppData
->maxVersion
= "1.*";
4112 if (mozilla::Version(mAppData
->minVersion
) > gToolkitVersion
||
4113 mozilla::Version(mAppData
->maxVersion
) < gToolkitVersion
) {
4115 "Error: Platform version '%s' is not compatible with\n"
4116 "minVersion >= %s\nmaxVersion <= %s\n",
4117 (const char*)gToolkitVersion
, (const char*)mAppData
->minVersion
,
4118 (const char*)mAppData
->maxVersion
);
4122 rv
= mDirProvider
.Initialize(mAppData
->directory
, mAppData
->xreDirectory
);
4123 if (NS_FAILED(rv
)) return 1;
4125 if (EnvHasValue("MOZ_CRASHREPORTER")) {
4126 mAppData
->flags
|= NS_XRE_ENABLE_CRASH_REPORTER
;
4129 nsCOMPtr
<nsIFile
> xreBinDirectory
;
4130 xreBinDirectory
= mDirProvider
.GetGREBinDir();
4132 if ((mAppData
->flags
& NS_XRE_ENABLE_CRASH_REPORTER
) &&
4133 NS_SUCCEEDED(CrashReporter::SetExceptionHandler(xreBinDirectory
))) {
4134 nsCOMPtr
<nsIFile
> file
;
4135 rv
= nsXREDirProvider::GetUserAppDataDirectory(getter_AddRefs(file
));
4136 if (NS_SUCCEEDED(rv
)) {
4137 CrashReporter::SetUserAppDataDirectory(file
);
4139 if (mAppData
->crashReporterURL
) {
4140 CrashReporter::SetServerURL(
4141 nsDependentCString(mAppData
->crashReporterURL
));
4144 // We overwrite this once we finish starting up.
4145 CrashReporter::RecordAnnotationBool(CrashReporter::Annotation::StartupCrash
,
4148 // pass some basic info from the app data
4149 if (mAppData
->vendor
) {
4150 CrashReporter::RecordAnnotationCString(CrashReporter::Annotation::Vendor
,
4153 if (mAppData
->name
) {
4154 CrashReporter::RecordAnnotationCString(
4155 CrashReporter::Annotation::ProductName
, mAppData
->name
);
4158 CrashReporter::RecordAnnotationCString(
4159 CrashReporter::Annotation::ProductID
, mAppData
->ID
);
4161 if (mAppData
->version
) {
4162 CrashReporter::RecordAnnotationCString(CrashReporter::Annotation::Version
,
4165 if (mAppData
->buildID
) {
4166 CrashReporter::RecordAnnotationCString(CrashReporter::Annotation::BuildID
,
4170 nsDependentCString
releaseChannel(MOZ_STRINGIFY(MOZ_UPDATE_CHANNEL
));
4171 CrashReporter::RecordAnnotationNSCString(
4172 CrashReporter::Annotation::ReleaseChannel
, releaseChannel
);
4175 nsAutoString appInitDLLs
;
4176 if (widget::WinUtils::GetAppInitDLLs(appInitDLLs
)) {
4177 CrashReporter::RecordAnnotationNSString(
4178 CrashReporter::Annotation::AppInitDLLs
, appInitDLLs
);
4181 nsString packageFamilyName
= widget::WinUtils::GetPackageFamilyName();
4182 if (StringBeginsWith(packageFamilyName
, u
"Mozilla."_ns
) ||
4183 StringBeginsWith(packageFamilyName
, u
"MozillaCorporation."_ns
)) {
4184 CrashReporter::RecordAnnotationNSCString(
4185 CrashReporter::Annotation::WindowsPackageFamilyName
,
4186 NS_ConvertUTF16toUTF8(packageFamilyName
));
4190 bool isBackgroundTaskMode
= false;
4191 #ifdef MOZ_BACKGROUNDTASKS
4192 Maybe
<nsCString
> backgroundTasks
= BackgroundTasks::GetBackgroundTasks();
4193 if (backgroundTasks
.isSome()) {
4194 isBackgroundTaskMode
= true;
4195 CrashReporter::RecordAnnotationNSCString(
4196 CrashReporter::Annotation::BackgroundTaskName
, backgroundTasks
.ref());
4199 CrashReporter::RecordAnnotationBool(
4200 CrashReporter::Annotation::BackgroundTaskMode
, isBackgroundTaskMode
);
4202 CrashReporter::RecordAnnotationBool(CrashReporter::Annotation::HeadlessMode
,
4203 gfxPlatform::IsHeadless());
4205 CrashReporter::SetRestartArgs(gArgc
, gArgv
);
4207 // annotate other data (user id etc)
4208 nsCOMPtr
<nsIFile
> userAppDataDir
;
4209 if (NS_SUCCEEDED(mDirProvider
.GetUserAppDataDirectory(
4210 getter_AddRefs(userAppDataDir
)))) {
4211 CrashReporter::SetupExtraData(userAppDataDir
,
4212 nsDependentCString(mAppData
->buildID
));
4214 // see if we have a crashreporter-override.ini in the application
4216 nsCOMPtr
<nsIFile
> overrideini
;
4218 mDirProvider
.GetAppDir()->Clone(getter_AddRefs(overrideini
))) &&
4220 overrideini
->AppendNative("crashreporter-override.ini"_ns
))) {
4222 nsAutoString overridePathW
;
4223 overrideini
->GetPath(overridePathW
);
4224 NS_ConvertUTF16toUTF8
overridePath(overridePathW
);
4226 nsAutoCString overridePath
;
4227 overrideini
->GetNativePath(overridePath
);
4230 SaveWordToEnv("MOZ_CRASHREPORTER_STRINGS_OVERRIDE", overridePath
);
4234 // We might have registered a runtime exception module very early in process
4235 // startup to catch early crashes. This is before we have access to ini file
4236 // data, so unregister here if it turns out the crash reporter is disabled.
4237 CrashReporter::UnregisterRuntimeExceptionModule();
4240 #if defined(MOZ_SANDBOX) && defined(XP_WIN)
4241 if (mAppData
->sandboxBrokerServices
) {
4242 nsAutoString binDirPath
;
4243 MOZ_ALWAYS_SUCCEEDS(xreBinDirectory
->GetPath(binDirPath
));
4244 SandboxBroker::Initialize(mAppData
->sandboxBrokerServices
, binDirPath
);
4246 # if defined(MOZ_SANDBOX)
4247 // If we're sandboxing content and we fail to initialize, then crashing here
4248 // seems like the sensible option.
4249 if (BrowserTabsRemoteAutostart()) {
4250 MOZ_CRASH("Failed to initialize broker services, can't continue.");
4253 // Otherwise just warn for the moment, as most things will work.
4255 "Failed to initialize broker services, sandboxed processes will "
4261 // Set up ability to respond to system (Apple) events. This must occur before
4262 // ProcessUpdates to ensure that links clicked in external applications aren't
4263 // lost when updates are pending.
4264 SetupMacApplicationDelegate(&gRestartedByOS
);
4266 if (EnvHasValue("MOZ_LAUNCHED_CHILD")) {
4267 // This is needed, on relaunch, to force the OS to use the "Cocoa Dock
4268 // API". Otherwise the call to ReceiveNextEvent() below will make it
4269 // use the "Carbon Dock API". For more info see bmo bug 377166.
4270 EnsureUseCocoaDockAPI();
4272 // When the app relaunches, the original process exits. This causes
4273 // the dock tile to stop bouncing, lose the "running" triangle, and
4274 // if the tile does not permanently reside in the Dock, even disappear.
4275 // This can be confusing to the user, who is expecting the app to launch.
4276 // Calling ReceiveNextEvent without requesting any event is enough to
4277 // cause a dock tile for the child process to appear.
4278 const EventTypeSpec kFakeEventList
[] = {{INT_MAX
, INT_MAX
}};
4280 ::ReceiveNextEvent(GetEventTypeCount(kFakeEventList
), kFakeEventList
,
4281 kEventDurationNoWait
, false, &event
);
4284 if (CheckArg("foreground")) {
4285 // The original process communicates that it was in the foreground by
4286 // adding this argument. This new process, which is taking over for
4287 // the old one, should make itself the active application.
4288 ProcessSerialNumber psn
;
4289 if (::GetCurrentProcess(&psn
) == noErr
) ::SetFrontProcess(&psn
);
4293 SaveToEnv("MOZ_LAUNCHED_CHILD=");
4295 // On Windows, the -os-restarted command line switch lets us know when we are
4296 // restarted via RegisterApplicationRestart. May be used for other OSes later.
4297 if (CheckArg("os-restarted", nullptr, CheckArgFlag::RemoveArg
) == ARG_FOUND
) {
4298 gRestartedByOS
= true;
4301 gRestartArgc
= gArgc
;
4303 (char**)malloc(sizeof(char*) * (gArgc
+ 1 + (override
? 2 : 0)));
4304 if (!gRestartArgv
) {
4309 for (i
= 0; i
< gArgc
; ++i
) {
4310 gRestartArgv
[i
] = gArgv
[i
];
4313 // Add the -override argument back (it is removed automatically be CheckArg)
4316 gRestartArgv
[gRestartArgc
++] = const_cast<char*>("-override");
4317 gRestartArgv
[gRestartArgc
++] = const_cast<char*>(override
);
4320 gRestartArgv
[gRestartArgc
] = nullptr;
4322 Maybe
<bool> safeModeRequested
= IsSafeModeRequested(gArgc
, gArgv
);
4323 if (!safeModeRequested
) {
4326 #ifdef MOZ_BACKGROUNDTASKS
4327 if (BackgroundTasks::IsBackgroundTaskMode()) {
4328 safeModeRequested
= Some(false);
4330 // Remove the --backgroundtask arg now that it has been saved in
4332 const char* tmpBackgroundTaskName
= nullptr;
4333 Unused
<< CheckArg("backgroundtask", &tmpBackgroundTaskName
,
4334 CheckArgFlag::RemoveArg
);
4338 gSafeMode
= safeModeRequested
.value();
4340 MaybeAddCPUMicrocodeCrashAnnotation();
4341 CrashReporter::RegisterAnnotationBool(CrashReporter::Annotation::SafeMode
,
4344 // Strip the now unsupported no-remote command line argument.
4345 CheckArg("no-remote");
4347 #if defined(MOZ_HAS_REMOTE)
4348 // Handle the --new-instance command line arguments. Setup the environment to
4349 // better accommodate other components and various restart scenarios.
4350 ar
= CheckArg("new-instance");
4351 if (ar
== ARG_FOUND
|| EnvHasValue("MOZ_NEW_INSTANCE")) {
4352 mDisableRemoteClient
= true;
4355 // These arguments do nothing in platforms with no remoting support but we
4356 // should remove them from the command line anyway.
4357 CheckArg("new-instance");
4360 ar
= CheckArg("offline");
4361 if (ar
|| EnvHasValue("XRE_START_OFFLINE")) {
4362 mStartOffline
= true;
4365 const char* origin
= nullptr;
4366 if (!PR_GetEnv("MOZ_FORCE_QUIC_ON") &&
4367 ARG_FOUND
== CheckArg("origin-to-force-quic-on", &origin
,
4368 CheckArgFlag::RemoveArg
)) {
4369 mOriginToForceQUIC
.Assign(origin
);
4372 // On Windows, to get working console arrangements so help/version/etc
4373 // print something, we need to initialize the native app support.
4374 rv
= NS_CreateNativeAppSupport(getter_AddRefs(mNativeApp
));
4375 if (NS_FAILED(rv
)) return 1;
4377 // Handle --help, --full-version and --version command line arguments.
4378 // They should return quickly, so we deal with them here.
4379 if (CheckArg("h") || CheckArg("help") || CheckArg("?")) {
4385 if (CheckArg("v") || CheckArg("version")) {
4391 if (CheckArg("full-version")) {
4397 #ifdef MOZ_ENABLE_DBUS
4398 const char* dbusServiceLauncher
= nullptr;
4399 ar
= CheckArg("dbus-service", &dbusServiceLauncher
, CheckArgFlag::None
);
4400 if (ar
== ARG_BAD
) {
4401 Output(true, "Missing launcher param for --dbus-service\n");
4404 if (ar
== ARG_FOUND
) {
4405 UniquePtr
<DBusService
> dbusService
=
4406 MakeUnique
<DBusService
>(dbusServiceLauncher
);
4407 if (dbusService
->Init()) {
4415 rv
= XRE_InitCommandLine(gArgc
, gArgv
);
4416 NS_ENSURE_SUCCESS(rv
, 1);
4421 #if defined(XP_LINUX) && !defined(ANDROID)
4423 static void AnnotateLSBRelease(void*) {
4424 nsCString dist
, desc
, release
, codename
;
4425 if (widget::lsb::GetLSBRelease(dist
, desc
, release
, codename
)) {
4426 CrashReporter::AppendAppNotesToCrashReport(desc
);
4430 #endif // defined(XP_LINUX) && !defined(ANDROID)
4433 static void ReadAheadSystemDll(const wchar_t* dllName
) {
4434 wchar_t dllPath
[MAX_PATH
];
4435 if (ConstructSystem32Path(dllName
, dllPath
, MAX_PATH
)) {
4436 ReadAheadLib(dllPath
);
4440 static void ReadAheadPackagedDll(const wchar_t* dllName
,
4441 const wchar_t* aGREDir
) {
4442 wchar_t dllPath
[MAX_PATH
];
4443 swprintf(dllPath
, MAX_PATH
, L
"%s\\%s", aGREDir
, dllName
);
4444 ReadAheadLib(dllPath
);
4447 static void PR_CALLBACK
ReadAheadDlls_ThreadStart(void* arg
) {
4448 UniquePtr
<wchar_t[]> greDir(static_cast<wchar_t*>(arg
));
4450 // In Bug 1628903, we investigated which DLLs we should prefetch in
4451 // order to reduce disk I/O and improve startup on Windows machines.
4452 // Our ultimate goal is to measure the impact of these improvements on
4453 // retention (see Bug 1640087). Before we place this within a pref,
4454 // we should ensure this feature only ships to the nightly channel
4455 // and monitor results from that subset.
4457 // Prefetch the DLLs shipped with firefox
4458 ReadAheadPackagedDll(L
"libegl.dll", greDir
.get());
4459 ReadAheadPackagedDll(L
"libGLESv2.dll", greDir
.get());
4460 ReadAheadPackagedDll(L
"nssckbi.dll", greDir
.get());
4461 ReadAheadPackagedDll(L
"freebl3.dll", greDir
.get());
4462 ReadAheadPackagedDll(L
"softokn3.dll", greDir
.get());
4464 // Prefetch the system DLLs
4465 ReadAheadSystemDll(L
"DWrite.dll");
4466 ReadAheadSystemDll(L
"D3DCompiler_47.dll");
4468 // Load DataExchange.dll and twinapi.appcore.dll for
4469 // nsWindow::EnableDragDrop
4470 ReadAheadSystemDll(L
"DataExchange.dll");
4471 ReadAheadSystemDll(L
"twinapi.appcore.dll");
4473 // Load twinapi.dll for WindowsUIUtils::UpdateTabletModeState
4474 ReadAheadSystemDll(L
"twinapi.dll");
4476 // Load explorerframe.dll for WinTaskbar::Initialize
4477 ReadAheadSystemDll(L
"ExplorerFrame.dll");
4479 // Load WinTypes.dll for nsOSHelperAppService::GetApplicationDescription
4480 ReadAheadSystemDll(L
"WinTypes.dll");
4485 #if defined(MOZ_UPDATER) && !defined(MOZ_WIDGET_ANDROID)
4486 enum struct ShouldNotProcessUpdatesReason
{
4489 OtherInstanceRunning
,
4493 const char* ShouldNotProcessUpdatesReasonAsString(
4494 ShouldNotProcessUpdatesReason aReason
) {
4496 case ShouldNotProcessUpdatesReason::DevToolsLaunching
:
4497 return "DevToolsLaunching";
4498 case ShouldNotProcessUpdatesReason::NotAnUpdatingTask
:
4499 return "NotAnUpdatingTask";
4500 case ShouldNotProcessUpdatesReason::OtherInstanceRunning
:
4501 return "OtherInstanceRunning";
4503 MOZ_CRASH("impossible value for ShouldNotProcessUpdatesReason");
4507 Maybe
<ShouldNotProcessUpdatesReason
> ShouldNotProcessUpdates(
4508 nsXREDirProvider
& aDirProvider
) {
4509 // Don't process updates when launched from the installer.
4510 // It's possible for a stale update to be present in the case of a paveover;
4511 // ignore it and leave the update service to discard it.
4512 if (ARG_FOUND
== CheckArgExists("first-startup")) {
4513 NS_WARNING("ShouldNotProcessUpdates(): FirstStartup");
4514 return Some(ShouldNotProcessUpdatesReason::FirstStartup
);
4517 // Do not process updates if we're launching devtools, as evidenced by
4518 // "--chrome ..." with the browser toolbox chrome document URL.
4520 // Keep this synchronized with the value of the same name in
4521 // devtools/client/framework/browser-toolbox/Launcher.sys.mjs. Or, for bonus
4522 // points, lift this value to nsIXulRuntime or similar, so that it can be
4523 // accessed in both locations. (The prefs service isn't available at this
4524 // point so the simplest manner of sharing the value is not available to us.)
4525 const char* BROWSER_TOOLBOX_WINDOW_URL
=
4526 "chrome://devtools/content/framework/browser-toolbox/window.html";
4528 const char* chromeParam
= nullptr;
4529 if (ARG_FOUND
== CheckArg("chrome", &chromeParam
, CheckArgFlag::None
)) {
4530 if (!chromeParam
|| !strcmp(BROWSER_TOOLBOX_WINDOW_URL
, chromeParam
)) {
4531 NS_WARNING("ShouldNotProcessUpdates(): DevToolsLaunching");
4532 return Some(ShouldNotProcessUpdatesReason::DevToolsLaunching
);
4536 # ifdef MOZ_BACKGROUNDTASKS
4537 // Do not process updates if we're running a background task mode and another
4538 // instance is already running. This avoids periodic maintenance updating
4539 // underneath a browsing session.
4540 Maybe
<nsCString
> backgroundTasks
= BackgroundTasks::GetBackgroundTasks();
4541 if (backgroundTasks
.isSome()) {
4542 // Only process updates for specific tasks: at this time, the
4543 // `backgroundupdate` task and the test-only `shouldprocessupdates` task.
4545 // Background tasks can be sparked by Firefox instances that are shutting
4546 // down, which can cause races between the task startup trying to update and
4547 // Firefox trying to invoke the updater. This happened when converting
4548 // `pingsender` to a background task, since it is launched to send pings at
4549 // shutdown: Bug 1736373.
4551 // We'd prefer to have this be a property of the task definition sibling to
4552 // `backgroundTaskTimeoutSec`, but when we reach this code we're well before
4553 // we can load the task JSM.
4554 if (!BackgroundTasks::IsUpdatingTaskName(backgroundTasks
.ref())) {
4555 NS_WARNING("ShouldNotProcessUpdates(): NotAnUpdatingTask");
4556 return Some(ShouldNotProcessUpdatesReason::NotAnUpdatingTask
);
4559 // At this point we have a dir provider but no XPCOM directory service. We
4560 // launch the update sync manager using that information so that it doesn't
4561 // need to ask for (and fail to find) the directory service.
4562 nsCOMPtr
<nsIFile
> anAppFile
;
4564 nsresult rv
= aDirProvider
.GetFile(XRE_EXECUTABLE_FILE
, &persistent
,
4565 getter_AddRefs(anAppFile
));
4566 if (NS_FAILED(rv
) || !anAppFile
) {
4567 // Strange, but not a reason to skip processing updates.
4571 auto updateSyncManager
= new nsUpdateSyncManager(anAppFile
);
4573 bool otherInstance
= false;
4574 updateSyncManager
->IsOtherInstanceRunning(&otherInstance
);
4575 if (otherInstance
) {
4576 NS_WARNING("ShouldNotProcessUpdates(): OtherInstanceRunning");
4577 return Some(ShouldNotProcessUpdatesReason::OtherInstanceRunning
);
4586 namespace mozilla::startup
{
4587 Result
<nsCOMPtr
<nsIFile
>, nsresult
> GetIncompleteStartupFile(nsIFile
* aProfLD
) {
4588 nsCOMPtr
<nsIFile
> crashFile
;
4589 MOZ_TRY(aProfLD
->Clone(getter_AddRefs(crashFile
)));
4590 MOZ_TRY(crashFile
->Append(FILE_STARTUP_INCOMPLETE
));
4591 return std::move(crashFile
);
4593 } // namespace mozilla::startup
4595 // Check whether the last startup attempt resulted in a crash or hang.
4596 // This is distinct from the definition of a startup crash from
4597 // nsAppStartup::TrackStartupCrashBegin.
4598 bool XREMain::CheckLastStartupWasCrash() {
4599 Result
<nsCOMPtr
<nsIFile
>, nsresult
> crashFile
=
4600 GetIncompleteStartupFile(mProfLD
);
4601 if (crashFile
.isErr()) {
4605 // Attempt to create the incomplete startup canary file. If the file already
4606 // exists, this fails, and we know the last startup was a crash. If it
4607 // doesn't already exist, it is created, and will be removed at the end of
4608 // the startup crash detection window.
4610 Unused
<< crashFile
.inspect()->OpenNSPRFileDesc(
4611 PR_WRONLY
| PR_CREATE_FILE
| PR_EXCL
, 0666, getter_Transfers(fd
));
4616 * XRE_mainStartup - Initializes the profile and various other services.
4617 * Main() will exit early if either return value != 0 or if aExitFlag is
4620 int XREMain::XRE_mainStartup(bool* aExitFlag
) {
4623 if (!aExitFlag
) return 1;
4627 mozilla::MacAutoreleasePool pool
;
4630 // Enable Telemetry IO Reporting on DEBUG, nightly and local builds,
4631 // but disable it on FUZZING builds and for ANDROID.
4635 mozilla::Telemetry::InitIOReporting(gAppData
->xreDirectory
);
4638 const char* releaseChannel
= MOZ_STRINGIFY(MOZ_UPDATE_CHANNEL
);
4639 if (strcmp(releaseChannel
, "nightly") == 0 ||
4640 strcmp(releaseChannel
, "default") == 0) {
4641 mozilla::Telemetry::InitIOReporting(gAppData
->xreDirectory
);
4645 # endif /* ANDROID */
4646 #endif /* FUZZING */
4649 // Enable the HeapEnableTerminationOnCorruption exploit mitigation. We ignore
4650 // the return code because it always returns success, although it has no
4651 // effect on Windows older than XP SP3.
4652 HeapSetInformation(NULL
, HeapEnableTerminationOnCorruption
, NULL
, 0);
4655 #ifdef MOZ_WIDGET_GTK
4656 // Stash startup token in owned memory because gtk_init will clear
4657 // DESKTOP_STARTUP_ID it.
4658 if (const char* v
= PR_GetEnv("DESKTOP_STARTUP_ID")) {
4659 mDesktopStartupID
.Assign(v
);
4661 if (const char* v
= PR_GetEnv("XDG_ACTIVATION_TOKEN")) {
4662 mXDGActivationToken
.Assign(v
);
4668 // Save the shortcut path before lpTitle is replaced by an AUMID,
4669 // such as by WinTaskbar
4671 GetStartupInfoW(&si
);
4672 if (si
.dwFlags
& STARTF_TITLEISAPPID
) {
4673 NS_WARNING("AUMID was already set, shortcut may have been lost.");
4674 } else if ((si
.dwFlags
& STARTF_TITLEISLINKNAME
) && si
.lpTitle
) {
4675 gProcessStartupShortcut
.Assign(si
.lpTitle
);
4680 #if defined(MOZ_WIDGET_GTK)
4681 // setup for private colormap. Ideally we'd like to do this
4682 // in nsAppShell::Create, but we need to get in before gtk
4683 // has been initialized to make sure everything is running
4686 // Set program name to the one defined in application.ini.
4687 g_set_prgname(gAppData
->remotingName
);
4689 // Initialize GTK here for splash.
4691 # if defined(MOZ_WIDGET_GTK) && defined(MOZ_X11)
4692 // Disable XInput2 multidevice support due to focus bugginess.
4693 // See bugs 1182700, 1170342.
4694 // gdk_disable_multidevice() affects Gdk X11 backend only,
4695 // the multidevice support is always enabled on Wayland backend.
4696 const char* useXI2
= PR_GetEnv("MOZ_USE_XINPUT2");
4697 if (!useXI2
|| (*useXI2
== '0')) gdk_disable_multidevice();
4700 // Open the display ourselves instead of using gtk_init, so that we can
4701 // close it without fear that one day gtk might clean up the display it
4703 if (!gtk_parse_args(&gArgc
, &gArgv
)) return 1;
4704 #endif /* MOZ_WIDGET_GTK */
4707 if (PR_GetEnv("FUZZER")) {
4709 return mozilla::fuzzerRunner
->Run(&gArgc
, &gArgv
);
4713 if (PR_GetEnv("MOZ_RUN_GTEST")) {
4718 // RunGTest will only be set if we're in xul-unit
4719 if (mozilla::RunGTest
) {
4721 result
= mozilla::RunGTest(&gArgc
, gArgv
);
4725 printf("TEST-UNEXPECTED-FAIL | gtest | Not compiled with enable-tests\n");
4731 bool isBackgroundTaskMode
= false;
4732 #ifdef MOZ_BACKGROUNDTASKS
4733 isBackgroundTaskMode
= BackgroundTasks::IsBackgroundTaskMode();
4736 #ifdef MOZ_HAS_REMOTE
4737 if (gfxPlatform::IsHeadless()) {
4738 mDisableRemoteClient
= true;
4743 // Init X11 in thread-safe mode. Must be called prior to the first call to
4744 // XOpenDisplay (called inside gdk_display_open). This is a requirement for
4745 // off main tread compositing.
4746 if (!isBackgroundTaskMode
&& !gfxPlatform::IsHeadless()) {
4750 #if defined(MOZ_WIDGET_GTK)
4751 if (!isBackgroundTaskMode
&& !gfxPlatform::IsHeadless()) {
4752 const char* display_name
= nullptr;
4753 bool saveDisplayArg
= false;
4755 // display_name is owned by gdk.
4756 display_name
= gdk_get_display_arg_name();
4757 bool waylandEnabled
= IsWaylandEnabled();
4759 if (!display_name
) {
4760 auto* proxyEnv
= getenv("MOZ_DISABLE_WAYLAND_PROXY");
4761 bool disableWaylandProxy
= proxyEnv
&& *proxyEnv
;
4762 if (!disableWaylandProxy
&& XRE_IsParentProcess() && waylandEnabled
) {
4764 if (MOZ_LOG_TEST(gWidgetWaylandLog
, mozilla::LogLevel::Debug
)) {
4765 WaylandProxy::SetVerbose(true);
4768 gWaylandProxy
= WaylandProxy::Create();
4769 if (gWaylandProxy
) {
4770 gWaylandProxy
->RunThread();
4776 // if --display argument is given make sure it's
4777 // also passed to ContentChild::Init() by MOZ_GDK_DISPLAY.
4779 SaveWordToEnv("MOZ_GDK_DISPLAY", nsDependentCString(display_name
));
4780 saveDisplayArg
= true;
4783 // On Wayland disabled builds read X11 DISPLAY env exclusively
4784 // and don't care about different displays.
4785 if (!waylandEnabled
&& !display_name
) {
4786 display_name
= PR_GetEnv("DISPLAY");
4787 if (!display_name
) {
4788 PR_fprintf(PR_STDERR
,
4789 "Error: no DISPLAY environment variable specified\n");
4795 GdkDisplay
* disp
= gdk_display_open(display_name
);
4797 PR_fprintf(PR_STDERR
, "Error: cannot open display: %s\n", display_name
);
4800 if (saveDisplayArg
) {
4801 if (GdkIsX11Display(disp
)) {
4802 SaveWordToEnv("DISPLAY", nsDependentCString(display_name
));
4803 } else if (GdkIsWaylandDisplay(disp
)) {
4804 SaveWordToEnv("WAYLAND_DISPLAY", nsDependentCString(display_name
));
4808 gdk_display_manager_open_display(gdk_display_manager_get(), nullptr);
4810 # if defined(MOZ_WAYLAND)
4811 // We want to use proxy for main connection only so
4812 // restore original Wayland display for next potential Wayland connections
4813 // from gfx probe code and so on.
4814 if (gWaylandProxy
) {
4815 gWaylandProxy
->RestoreWaylandDisplay();
4817 if (waylandEnabled
&& PR_GetEnv("WAYLAND_DISPLAY") && GdkIsX11Display()) {
4818 // Gtk somehow switched to X11 display but we want Wayland.
4819 // It may happen if compositor response is missig or it's slow
4820 // or WAYLAND_DISPLAY is wrong. In such case throw warning but
4823 "Error: Failed to open Wayland display, fallback to X11. "
4824 "WAYLAND_DISPLAY='%s' DISPLAY='%s'\n",
4825 PR_GetEnv("WAYLAND_DISPLAY"), PR_GetEnv("DISPLAY"));
4827 // We need to unset WAYLAND_DISPLAY. Gfx probe code doesn't have fallback
4828 // to X11 and we'll end with Browser running SW rendering only then.
4829 g_unsetenv("WAYLAND_DISPLAY");
4830 gWaylandProxy
= nullptr;
4833 if (!gdk_display_get_default()) {
4835 "Error: we don't have any display, WAYLAND_DISPLAY='%s' "
4837 PR_GetEnv("WAYLAND_DISPLAY"), PR_GetEnv("DISPLAY"));
4840 // Check that Wayland only and X11 only builds
4841 // use appropriate displays.
4842 # if defined(MOZ_WAYLAND) && !defined(MOZ_X11)
4843 if (!GdkIsWaylandDisplay()) {
4844 Output(true, "Wayland only build is missig Wayland display!\n");
4848 # if !defined(MOZ_WAYLAND) && defined(MOZ_X11)
4849 if (!GdkIsX11Display()) {
4850 Output(true, "X11 only build is missig X11 display!\n");
4856 #if defined(MOZ_HAS_REMOTE)
4857 // handle --remote now that xpcom is fired up
4858 gRemoteService
= new nsRemoteService(gAppData
->remotingName
);
4859 if (gRemoteService
) {
4860 gRemoteService
->LockStartup();
4863 #if defined(MOZ_WIDGET_GTK)
4864 g_set_application_name(mAppData
->name
);
4866 #endif /* defined(MOZ_WIDGET_GTK) */
4868 // Do this after initializing GDK, or GDK will install its own handler.
4869 XRE_InstallX11ErrorHandler();
4872 // Call the code to install our handler
4874 setupProfilingStuff();
4877 bool canRun
= false;
4878 rv
= mNativeApp
->Start(&canRun
);
4879 if (NS_FAILED(rv
) || !canRun
) {
4883 #ifdef MOZ_WIDGET_GTK
4884 // startup token might be cleared now, we recover it in case we need a
4886 if (!mDesktopStartupID
.IsEmpty()) {
4887 // Leak it with extreme prejudice!
4888 PR_SetEnv(ToNewCString("DESKTOP_STARTUP_ID="_ns
+ mDesktopStartupID
));
4891 if (!mXDGActivationToken
.IsEmpty()) {
4892 // Leak it with extreme prejudice!
4893 PR_SetEnv(ToNewCString("XDG_ACTIVATION_TOKEN="_ns
+ mXDGActivationToken
));
4897 // Support exiting early for testing startup sequence. Bug 1360493
4898 if (CheckArg("test-launch-without-hang")) {
4903 mProfileSvc
= NS_GetToolkitProfileService();
4905 // We failed to choose or create profile - notify user and quit
4906 ProfileMissingDialog(mNativeApp
);
4910 bool wasDefaultSelection
;
4911 nsCOMPtr
<nsIToolkitProfile
> profile
;
4912 rv
= SelectProfile(mProfileSvc
, mNativeApp
, getter_AddRefs(mProfD
),
4913 getter_AddRefs(mProfLD
), getter_AddRefs(profile
),
4914 &wasDefaultSelection
);
4915 if (rv
== NS_ERROR_LAUNCHED_CHILD_PROCESS
|| rv
== NS_ERROR_ABORT
) {
4920 if (NS_FAILED(rv
)) {
4921 // We failed to choose or create profile - notify user and quit
4922 ProfileMissingDialog(mNativeApp
);
4926 #if defined(MOZ_HAS_REMOTE)
4927 if (gRemoteService
) {
4928 // Use the full profile path to identify the profile.
4929 nsCString profilePath
;
4933 rv
= mProfD
->GetPath(path
);
4934 if (NS_SUCCEEDED(rv
)) {
4935 CopyUTF16toUTF8(path
, profilePath
);
4938 rv
= mProfD
->GetNativePath(profilePath
);
4941 if (NS_SUCCEEDED(rv
)) {
4942 gRemoteService
->SetProfile(profilePath
);
4944 if (!mDisableRemoteClient
) {
4945 // Try to remote the entire command line. If this fails, start up
4947 # ifdef MOZ_WIDGET_GTK
4948 auto& startupToken
=
4949 GdkIsWaylandDisplay() ? mXDGActivationToken
: mDesktopStartupID
;
4951 if (GdkIsX11Display() && startupToken
.IsEmpty()) {
4952 startupToken
= SynthesizeStartupToken();
4954 # endif /* MOZ_X11 */
4955 gRemoteService
->SetStartupToken(startupToken
);
4957 rv
= gRemoteService
->StartClient();
4959 if (rv
== NS_ERROR_NOT_AVAILABLE
&& profile
) {
4960 // Older versions would use the profile name in preference to the
4962 nsCString profileName
;
4963 profile
->GetName(profileName
);
4964 gRemoteService
->SetProfile(profileName
);
4966 rv
= gRemoteService
->StartClient();
4968 // Reset back to the path.
4969 gRemoteService
->SetProfile(profilePath
);
4972 if (NS_SUCCEEDED(rv
)) {
4974 gRemoteService
->UnlockStartup();
4978 if (rv
== NS_ERROR_INVALID_ARG
) {
4979 gRemoteService
->UnlockStartup();
4987 #if defined(MOZ_UPDATER) && !defined(MOZ_WIDGET_ANDROID)
4990 // When automatically restarting for a staged background update
4991 // we want the child process to wait here so that the updater
4992 // does not register two instances running and use that as a
4993 // reason to not process updates. This function requires having
4994 // -restart-pid <param> in the command line to function properly.
4995 // Ensure we keep -restart-pid if we are running tests
4996 if (ARG_FOUND
== CheckArgExists("restart-pid") &&
4997 !CheckArg("test-only-automatic-restart-no-wait")) {
4998 // We're not testing and can safely remove it now and read the pid.
4999 const char* restartPidString
= nullptr;
5000 CheckArg("restart-pid", &restartPidString
, CheckArgFlag::RemoveArg
);
5001 // pid should be first parameter following -restart-pid.
5002 uint32_t pid
= nsDependentCString(restartPidString
).ToInteger(&rv
, 10U);
5003 if (NS_SUCCEEDED(rv
) && pid
> 0) {
5005 "*** MaybeWaitForProcessExit: launched pidDWORD = %u ***\n", pid
);
5006 RefPtr
<nsUpdateProcessor
> updater
= new nsUpdateProcessor();
5008 updater
->WaitForProcessExit(pid
, MAYBE_WAIT_TIMEOUT_MS
))) {
5009 NS_WARNING("Failed to MaybeWaitForProcessExit.");
5012 NS_WARNING("Failed to parse pid from -restart-pid.");
5017 Maybe
<ShouldNotProcessUpdatesReason
> shouldNotProcessUpdatesReason
=
5018 ShouldNotProcessUpdates(mDirProvider
);
5019 if (shouldNotProcessUpdatesReason
.isNothing()) {
5020 // Check for and process any available updates
5021 nsCOMPtr
<nsIFile
> updRoot
;
5023 rv
= mDirProvider
.GetFile(XRE_UPDATE_ROOT_DIR
, &persistent
,
5024 getter_AddRefs(updRoot
));
5025 // XRE_UPDATE_ROOT_DIR may fail. Fallback to appDir if failed
5026 if (NS_FAILED(rv
)) {
5027 updRoot
= mDirProvider
.GetAppDir();
5030 // If the MOZ_TEST_PROCESS_UPDATES environment variable already exists, then
5031 // we are being called from the callback application.
5032 if (EnvHasValue("MOZ_TEST_PROCESS_UPDATES")) {
5033 // If the caller has asked us to log our arguments, do so. This is used
5034 // to make sure that the maintenance service successfully launches the
5035 // callback application.
5036 const char* logFile
= nullptr;
5037 if (ARG_FOUND
== CheckArg("dump-args", &logFile
)) {
5038 FILE* logFP
= fopen(logFile
, "wb");
5040 for (int i
= 1; i
< gRestartArgc
; ++i
) {
5041 fprintf(logFP
, "%s\n", gRestartArgv
[i
]);
5050 // Support for processing an update and exiting. The
5051 // MOZ_TEST_PROCESS_UPDATES environment variable will be part of the
5052 // updater's environment and the application that is relaunched by the
5053 // updater. When the application is relaunched by the updater it will be
5054 // removed below and the application will exit.
5055 if (CheckArg("test-process-updates")) {
5056 SaveToEnv("MOZ_TEST_PROCESS_UPDATES=1");
5058 nsCOMPtr
<nsIFile
> exeFile
, exeDir
;
5059 rv
= mDirProvider
.GetFile(XRE_EXECUTABLE_FILE
, &persistent
,
5060 getter_AddRefs(exeFile
));
5061 NS_ENSURE_SUCCESS(rv
, 1);
5062 rv
= exeFile
->GetParent(getter_AddRefs(exeDir
));
5063 NS_ENSURE_SUCCESS(rv
, 1);
5064 ProcessUpdates(mDirProvider
.GetGREDir(), exeDir
, updRoot
, gRestartArgc
,
5065 gRestartArgv
, mAppData
->version
);
5066 if (EnvHasValue("MOZ_TEST_PROCESS_UPDATES")) {
5067 SaveToEnv("MOZ_TEST_PROCESS_UPDATES=");
5072 if (CheckArg("test-process-updates") ||
5073 EnvHasValue("MOZ_TEST_PROCESS_UPDATES")) {
5074 // Support for testing *not* processing an update. The launched process
5075 // can witness this environment variable and conclude that its runtime
5076 // environment resulted in not processing updates.
5078 SaveToEnv(nsPrintfCString(
5079 "MOZ_TEST_PROCESS_UPDATES=ShouldNotProcessUpdates(): %s",
5080 ShouldNotProcessUpdatesReasonAsString(
5081 shouldNotProcessUpdatesReason
.value()))
5087 bool useSelectedProfile
;
5088 rv
= mProfileSvc
->GetStartWithLastProfile(&useSelectedProfile
);
5089 NS_ENSURE_SUCCESS(rv
, 1);
5091 // We now know there is no existing instance using the selected profile. If
5092 // the profile wasn't selected by specific command line arguments and the
5093 // user has chosen to show the profile manager on startup then do that.
5094 if (wasDefaultSelection
&& !useSelectedProfile
) {
5095 rv
= ShowProfileManager(mProfileSvc
, mNativeApp
);
5096 } else if (profile
) {
5097 bool showSelector
= false;
5098 profile
->GetShowProfileSelector(&showSelector
);
5100 rv
= ShowProfileSelector(mProfileSvc
, mNativeApp
);
5106 if (rv
== NS_ERROR_LAUNCHED_CHILD_PROCESS
|| rv
== NS_ERROR_ABORT
) {
5110 if (NS_FAILED(rv
)) {
5114 // We always want to lock the profile even if we're actually going to reset
5116 rv
= LockProfile(mNativeApp
, mProfD
, mProfLD
, profile
,
5117 getter_AddRefs(mProfileLock
));
5118 if (rv
== NS_ERROR_LAUNCHED_CHILD_PROCESS
|| rv
== NS_ERROR_ABORT
) {
5121 } else if (NS_FAILED(rv
)) {
5125 if (gDoProfileReset
) {
5126 if (EnvHasValue("MOZ_RESET_PROFILE_RESTART")) {
5127 SaveToEnv("MOZ_RESET_PROFILE_RESTART=");
5128 // We only want to restore the previous session if the profile refresh was
5129 // triggered by user. And if it was a user-triggered profile refresh
5130 // through, say, the safeMode dialog or the troubleshooting page, the
5131 // MOZ_RESET_PROFILE_RESTART env variable would be set. Hence we set
5132 // MOZ_RESET_PROFILE_MIGRATE_SESSION here so that Firefox profile migrator
5133 // would migrate old session data later.
5134 SaveToEnv("MOZ_RESET_PROFILE_MIGRATE_SESSION=1");
5136 // Unlock the source profile.
5137 mProfileLock
->Unlock();
5139 // If we're resetting a profile, create a new one and use it to startup.
5140 gResetOldProfile
= profile
;
5141 rv
= mProfileSvc
->CreateResetProfile(getter_AddRefs(profile
));
5142 if (NS_SUCCEEDED(rv
)) {
5143 rv
= profile
->GetRootDir(getter_AddRefs(mProfD
));
5144 NS_ENSURE_SUCCESS(rv
, 1);
5145 SaveFileToEnv("XRE_PROFILE_PATH", mProfD
);
5147 rv
= profile
->GetLocalDir(getter_AddRefs(mProfLD
));
5148 NS_ENSURE_SUCCESS(rv
, 1);
5149 SaveFileToEnv("XRE_PROFILE_LOCAL_PATH", mProfLD
);
5151 // Lock the new profile
5152 rv
= LockProfile(mNativeApp
, mProfD
, mProfLD
, profile
,
5153 getter_AddRefs(mProfileLock
));
5154 if (rv
== NS_ERROR_LAUNCHED_CHILD_PROCESS
|| rv
== NS_ERROR_ABORT
) {
5157 } else if (NS_FAILED(rv
)) {
5161 NS_WARNING("Profile reset failed.");
5166 gProfileLock
= mProfileLock
;
5168 nsAutoCString version
;
5169 BuildVersion(version
);
5171 #ifdef TARGET_OS_ABI
5172 constexpr auto osABI
= nsLiteralCString
{TARGET_OS_ABI
};
5174 // No TARGET_XPCOM_ABI, but at least the OS is known
5175 constexpr auto osABI
= nsLiteralCString
{OS_TARGET
"_UNKNOWN"};
5178 // Check for version compatibility with the last version of the app this
5179 // profile was started with. The format of the version stamp is defined
5180 // by the BuildVersion function.
5181 // Also check to see if something has happened to invalidate our
5182 // fastload caches, like an app upgrade.
5184 // If we see .purgecaches, that means someone did a make.
5185 // Re-register components to catch potential changes.
5186 nsCOMPtr
<nsIFile
> flagFile
;
5187 if (mAppData
->directory
) {
5188 Unused
<< mAppData
->directory
->Clone(getter_AddRefs(flagFile
));
5191 flagFile
->AppendNative(FILE_INVALIDATE_CACHES
);
5196 nsCString lastVersion
;
5197 bool versionOK
= CheckCompatibility(
5198 mProfD
, version
, osABI
, mDirProvider
.GetGREDir(), mAppData
->directory
,
5199 flagFile
, &cachesOK
, &isDowngrade
, lastVersion
);
5201 MOZ_RELEASE_ASSERT(!cachesOK
|| lastVersion
.Equals(version
),
5202 "Caches cannot be good if the version has changed.");
5204 #ifdef MOZ_BLOCK_PROFILE_DOWNGRADE
5205 // The argument check must come first so the argument is always removed from
5206 // the command line regardless of whether this is a downgrade or not.
5207 if (!CheckArg("allow-downgrade") && isDowngrade
&&
5208 !EnvHasValue("MOZ_ALLOW_DOWNGRADE")) {
5212 rv
= CheckDowngrade(mProfD
, mNativeApp
, mProfileSvc
, lastVersion
);
5213 if (rv
== NS_ERROR_LAUNCHED_CHILD_PROCESS
|| rv
== NS_ERROR_ABORT
) {
5220 rv
= mDirProvider
.SetProfile(mProfD
, mProfLD
);
5221 NS_ENSURE_SUCCESS(rv
, 1);
5223 //////////////////////// NOW WE HAVE A PROFILE ////////////////////////
5225 mozilla::Telemetry::SetProfileDir(mProfD
);
5227 if (mAppData
->flags
& NS_XRE_ENABLE_CRASH_REPORTER
) {
5228 MakeOrSetMinidumpPath(mProfD
);
5231 CrashReporter::SetProfileDirectory(mProfD
);
5233 #ifdef MOZ_ASAN_REPORTER
5234 // In ASan reporter builds, we need to set ASan's log_path as early as
5235 // possible, so it dumps its errors into files there instead of using
5236 // the default stderr location. Since this is crucial for ASan reporter
5237 // to work at all (and we don't want people to use a non-functional
5238 // ASan reporter build), all failures while setting log_path are fatal.
5239 setASanReporterPath(mProfD
);
5241 // Export to env for child processes
5242 SaveFileToEnv("ASAN_REPORTER_PATH", mProfD
);
5245 bool lastStartupWasCrash
= CheckLastStartupWasCrash();
5247 CrashReporter::RecordAnnotationBool(
5248 CrashReporter::Annotation::LastStartupWasCrash
, lastStartupWasCrash
);
5250 if (CheckArg("purgecaches") || PR_GetEnv("MOZ_PURGE_CACHES") ||
5251 lastStartupWasCrash
|| gSafeMode
) {
5255 CrashReporter::RecordAnnotationBool(
5256 CrashReporter::Annotation::StartupCacheValid
, cachesOK
&& versionOK
);
5258 // Every time a profile is loaded by a build with a different version,
5259 // it updates the compatibility.ini file saying what version last wrote
5260 // the fastload caches. On subsequent launches if the version matches,
5261 // there is no need for re-registration. If the user loads the same
5262 // profile in different builds the component registry must be
5263 // re-generated to prevent mysterious component loading failures.
5265 bool startupCacheValid
= true;
5267 if (!cachesOK
|| !versionOK
) {
5268 QuotaManager::InvalidateQuotaCache();
5270 startupCacheValid
= RemoveComponentRegistries(mProfD
, mProfLD
, false);
5272 // Rewrite compatibility.ini to match the current build. The next run
5273 // should attempt to invalidate the caches if either this run is safe mode
5274 // or the attempt to invalidate the caches this time failed.
5275 WriteVersion(mProfD
, version
, osABI
, mDirProvider
.GetGREDir(),
5276 mAppData
->directory
, gSafeMode
|| !startupCacheValid
);
5279 if (!startupCacheValid
) StartupCache::IgnoreDiskCache();
5282 flagFile
->Remove(true);
5285 // Flush any pending page load events.
5286 mozilla::glean_pings::Pageload
.Submit("startup"_ns
);
5288 if (!isBackgroundTaskMode
) {
5290 GfxInfo::FireGLXTestProcess();
5293 // Make sure we have wayland connection for main thread.
5294 // It's used as template to create display connections
5295 // for different threads.
5296 if (IsWaylandEnabled()) {
5297 MOZ_UNUSED(WaylandDisplayGet());
5300 #ifdef MOZ_WIDGET_GTK
5301 nsAppShell::InstallTermSignalHandler();
5308 #if defined(MOZ_SANDBOX)
5309 void AddSandboxAnnotations() {
5310 CrashReporter::RecordAnnotationU32(
5311 CrashReporter::Annotation::ContentSandboxLevel
,
5312 GetEffectiveContentSandboxLevel());
5313 CrashReporter::RecordAnnotationU32(CrashReporter::Annotation::GpuSandboxLevel
,
5314 GetEffectiveGpuSandboxLevel());
5316 // Include whether or not this instance is capable of content sandboxing
5317 bool sSandboxCapable
= false;
5319 # if defined(XP_WIN)
5320 // All supported Windows versions support some level of content sandboxing
5321 sSandboxCapable
= true;
5322 # elif defined(XP_MACOSX)
5323 // All supported OS X versions are capable
5324 sSandboxCapable
= true;
5325 # elif defined(XP_LINUX)
5326 sSandboxCapable
= SandboxInfo::Get().CanSandboxContent();
5327 # elif defined(__OpenBSD__)
5328 sSandboxCapable
= true;
5329 StartOpenBSDSandbox(GeckoProcessType_Default
);
5332 CrashReporter::RecordAnnotationBool(
5333 CrashReporter::Annotation::ContentSandboxCapable
, sSandboxCapable
);
5335 #endif /* MOZ_SANDBOX */
5338 * XRE_mainRun - Command line startup, profile migration, and
5339 * the calling of appStartup->Run().
5341 nsresult
XREMain::XRE_mainRun() {
5342 nsresult rv
= NS_OK
;
5343 NS_ASSERTION(mScopedXPCOM
, "Scoped xpcom not initialized.");
5346 RefPtr
<mozilla::DllServices
> dllServices(mozilla::DllServices::Get());
5347 dllServices
->StartUntrustedModulesProcessor(false);
5348 auto dllServicesDisable
=
5349 MakeScopeExit([&dllServices
]() { dllServices
->DisableFull(); });
5351 mozilla::mscom::InitProfilerMarkers();
5352 #endif // defined(XP_WIN)
5354 // We need the appStartup pointer to span multiple scopes, so we declare
5356 nsCOMPtr
<nsIAppStartup
> appStartup
;
5357 // Ditto with the command line.
5358 nsCOMPtr
<nsICommandLineRunner
> cmdLine
;
5362 // In this scope, create an autorelease pool that will leave scope with
5363 // it just before entering our event loop.
5364 mozilla::MacAutoreleasePool pool
;
5367 rv
= mScopedXPCOM
->SetWindowCreator(mNativeApp
);
5368 NS_ENSURE_SUCCESS(rv
, NS_ERROR_FAILURE
);
5370 // tell the crash reporter to also send the release channel
5371 nsCOMPtr
<nsIPrefService
> prefs
=
5372 do_GetService("@mozilla.org/preferences-service;1", &rv
);
5373 if (NS_SUCCEEDED(rv
)) {
5374 nsCOMPtr
<nsIPrefBranch
> defaultPrefBranch
;
5375 rv
= prefs
->GetDefaultBranch(nullptr, getter_AddRefs(defaultPrefBranch
));
5377 if (NS_SUCCEEDED(rv
)) {
5379 rv
= defaultPrefBranch
->GetCharPref("app.update.channel", sval
);
5380 if (NS_SUCCEEDED(rv
)) {
5381 CrashReporter::RecordAnnotationNSCString(
5382 CrashReporter::Annotation::ReleaseChannel
, sval
);
5386 // Needs to be set after xpcom initialization.
5387 bool includeContextHeap
= Preferences::GetBool(
5388 "toolkit.crashreporter.include_context_heap", false);
5389 CrashReporter::SetIncludeContextHeap(includeContextHeap
);
5391 #if defined(XP_LINUX) && !defined(ANDROID)
5392 PR_CreateThread(PR_USER_THREAD
, AnnotateLSBRelease
, 0, PR_PRIORITY_LOW
,
5393 PR_GLOBAL_THREAD
, PR_UNJOINABLE_THREAD
, 0);
5396 if (mStartOffline
) {
5397 nsCOMPtr
<nsIIOService
> io(
5398 do_GetService("@mozilla.org/network/io-service;1"));
5399 NS_ENSURE_TRUE(io
, NS_ERROR_FAILURE
);
5400 io
->SetManageOfflineStatus(false);
5401 io
->SetOffline(true);
5404 if (!mOriginToForceQUIC
.IsEmpty()) {
5405 PR_SetEnv(ToNewCString("MOZ_FORCE_QUIC_ON="_ns
+ mOriginToForceQUIC
));
5409 mozilla::DllPrefetchExperimentRegistryInfo prefetchRegInfo
;
5410 mozilla::AlteredDllPrefetchMode dllPrefetchMode
=
5411 prefetchRegInfo
.GetAlteredDllPrefetchMode();
5413 if (!PR_GetEnv("XRE_NO_DLL_READAHEAD") &&
5414 dllPrefetchMode
!= mozilla::AlteredDllPrefetchMode::NoPrefetch
) {
5415 nsCOMPtr
<nsIFile
> greDir
= mDirProvider
.GetGREDir();
5417 rv
= greDir
->GetPath(path
);
5418 if (NS_SUCCEEDED(rv
)) {
5419 PRThread
* readAheadThread
;
5422 // We use the presence of a path argument inside the thread to determine
5423 // which list of Dlls to use. The old list does not need access to the
5424 // GRE dir, so the path argument is set to a null pointer.
5425 if (dllPrefetchMode
==
5426 mozilla::AlteredDllPrefetchMode::OptimizedPrefetch
) {
5427 pathRaw
= new wchar_t[MAX_PATH
];
5428 wcscpy_s(pathRaw
, MAX_PATH
, path
.get());
5432 readAheadThread
= PR_CreateThread(
5433 PR_USER_THREAD
, ReadAheadDlls_ThreadStart
, (void*)pathRaw
,
5434 PR_PRIORITY_NORMAL
, PR_GLOBAL_THREAD
, PR_UNJOINABLE_THREAD
, 0);
5435 if (readAheadThread
== NULL
) {
5443 nsCOMPtr
<nsIFile
> file
;
5444 mDirProvider
.GetAppDir()->Clone(getter_AddRefs(file
));
5445 file
->AppendNative("override.ini"_ns
);
5447 nsresult rv
= parser
.Init(file
);
5448 // if override.ini doesn't exist, also check for distribution.ini
5449 if (NS_FAILED(rv
)) {
5451 mDirProvider
.GetFile(XRE_APP_DISTRIBUTION_DIR
, &persistent
,
5452 getter_AddRefs(file
));
5453 file
->AppendNative("distribution.ini"_ns
);
5454 rv
= parser
.Init(file
);
5456 if (NS_SUCCEEDED(rv
)) {
5458 rv
= parser
.GetString("XRE", "EnableProfileMigrator", buf
);
5459 if (NS_SUCCEEDED(rv
)) {
5460 if (buf
[0] == '0' || buf
[0] == 'f' || buf
[0] == 'F') {
5461 gDoMigration
= false;
5467 // We'd like to initialize the JSContext *after* reading the user prefs.
5468 // Unfortunately that's not possible if we have to do profile migration
5469 // because that requires us to execute JS before reading user prefs.
5470 // Restarting the browser after profile migration would fix this. See
5472 bool initializedJSContext
= false;
5475 // Profile Migration
5476 if (mAppData
->flags
& NS_XRE_ENABLE_PROFILE_MIGRATOR
&& gDoMigration
) {
5477 gDoMigration
= false;
5479 xpc::InitializeJSContext();
5480 initializedJSContext
= true;
5482 nsCOMPtr
<nsIProfileMigrator
> pm(
5483 do_CreateInstance(NS_PROFILEMIGRATOR_CONTRACTID
));
5486 nsAutoCString aName
;
5487 if (gDoProfileReset
) {
5488 // Automatically migrate from the current application if we just
5489 // reset the profile.
5490 aKey
= MOZ_APP_NAME
;
5491 gResetOldProfile
->GetName(aName
);
5494 // Necessary for migration wizard to be accessible.
5497 pm
->Migrate(&mDirProvider
, aKey
, aName
);
5501 if (gDoProfileReset
) {
5502 if (!initializedJSContext
) {
5503 xpc::InitializeJSContext();
5504 initializedJSContext
= true;
5507 nsresult backupCreated
=
5508 ProfileResetCleanup(mProfileSvc
, gResetOldProfile
);
5509 if (NS_FAILED(backupCreated
)) {
5510 NS_WARNING("Could not cleanup the profile that was reset");
5515 // Initialize user preferences before notifying startup observers so they're
5516 // ready in time for early consumers, such as the component loader.
5517 mDirProvider
.InitializeUserPrefs();
5519 // Now that all (user) prefs have been loaded we can initialize the main
5520 // thread's JSContext.
5521 if (!initializedJSContext
) {
5522 xpc::InitializeJSContext();
5525 // Finally, now that JS has been initialized, we can finish pref loading.
5526 // This needs to happen after JS and XPConnect initialization because
5527 // AutoConfig files require JS execution. Note that this means AutoConfig
5528 // files can't override JS engine start-up prefs.
5529 mDirProvider
.FinishInitializingUserPrefs();
5531 // Do a canary load of a JS based module here. This will help us detect
5532 // missing resources during startup and make us react appropriate, that
5533 // is inform the user before exiting with a crash.
5535 mozilla::dom::AutoJSAPI jsapi
;
5536 MOZ_ALWAYS_TRUE(jsapi
.Init(xpc::PrivilegedJunkScope()));
5537 JS::Rooted
<JSObject
*> mod(jsapi
.cx());
5538 // AppConstants.sys.mjs is small, widely used and most likely will
5540 rv
= mozJSModuleLoader::Get()->ImportESModule(
5541 jsapi
.cx(), "resource://gre/modules/AppConstants.sys.mjs"_ns
, &mod
);
5542 if (NS_FAILED(rv
)) {
5543 return NS_ERROR_OMNIJAR_OR_DIR_MISSING
;
5547 #if defined(MOZ_SANDBOX) && defined(XP_WIN)
5548 // Now that we have preferences and the directory provider, we can
5549 // finish initializing SandboxBroker. This must happen before the GFX
5550 // platform is initialized (which will launch the GPU process), which
5551 // occurs when the "app-startup" category is started up below
5553 // After this completes, we are ready to launch sandboxed processes
5554 mozilla::SandboxBroker::GeckoDependentInitialize();
5557 nsCOMPtr
<nsIFile
> workingDir
;
5558 rv
= NS_GetSpecialDirectory(NS_OS_CURRENT_WORKING_DIR
,
5559 getter_AddRefs(workingDir
));
5560 if (NS_FAILED(rv
)) {
5561 // No working dir? This can happen if it gets deleted before we start.
5562 workingDir
= nullptr;
5565 cmdLine
= new nsCommandLine();
5567 rv
= cmdLine
->Init(gArgc
, gArgv
, workingDir
,
5568 nsICommandLine::STATE_INITIAL_LAUNCH
);
5569 NS_ENSURE_SUCCESS(rv
, NS_ERROR_FAILURE
);
5571 // "app-startup" is the name of both the category and the event
5572 NS_CreateServicesFromCategory("app-startup", cmdLine
, "app-startup",
5575 appStartup
= components::AppStartup::Service();
5576 NS_ENSURE_TRUE(appStartup
, NS_ERROR_FAILURE
);
5578 mDirProvider
.DoStartup();
5581 // It needs to be called on the main thread because it has to use
5582 // nsObserverService.
5583 EnsureWin32kInitialized();
5586 // As FilePreferences need the profile directory, we must initialize right
5588 mozilla::FilePreferences::InitDirectoriesAllowlist();
5589 mozilla::FilePreferences::InitPrefs();
5591 nsCString userAgentLocale
;
5592 LocaleService::GetInstance()->GetAppLocaleAsBCP47(userAgentLocale
);
5593 CrashReporter::RecordAnnotationNSCString(
5594 CrashReporter::Annotation::useragent_locale
, userAgentLocale
);
5596 if (!AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed
)) {
5597 /* Special-case services that need early access to the command
5599 nsCOMPtr
<nsIObserverService
> obsService
=
5600 mozilla::services::GetObserverService();
5602 obsService
->NotifyObservers(cmdLine
, "command-line-startup", nullptr);
5607 // Hack to sync up the various environment storages. XUL_APP_FILE is special
5608 // in that it comes from a different CRT (firefox.exe's static-linked copy).
5609 // Ugly details in http://bugzil.la/1175039#c27
5610 char appFile
[MAX_PATH
];
5611 if (GetEnvironmentVariableA("XUL_APP_FILE", appFile
, sizeof(appFile
))) {
5612 SmprintfPointer saved
= mozilla::Smprintf("XUL_APP_FILE=%s", appFile
);
5613 // We intentionally leak the string here since it is required by
5615 PR_SetEnv(saved
.release());
5619 mozilla::AppShutdown::SaveEnvVarsForPotentialRestart();
5621 // clear out any environment variables which may have been set
5622 // during the relaunch process now that we know we won't be relaunching.
5623 SaveToEnv("XRE_PROFILE_PATH=");
5624 SaveToEnv("XRE_PROFILE_LOCAL_PATH=");
5625 SaveToEnv("XRE_START_OFFLINE=");
5626 SaveToEnv("XUL_APP_FILE=");
5627 SaveToEnv("XRE_BINARY_PATH=");
5628 SaveToEnv("XRE_RESTARTED_BY_PROFILE_MANAGER=");
5630 if (!AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed
)) {
5631 // Don't create the hidden window during startup on
5632 // platforms that don't always need it.
5634 bool lazyHiddenWindow
= false;
5636 bool lazyHiddenWindow
= true;
5639 #ifdef MOZ_BACKGROUNDTASKS
5640 if (BackgroundTasks::IsBackgroundTaskMode()) {
5641 // Background tasks aren't going to load a chrome XUL document.
5642 lazyHiddenWindow
= true;
5646 if (!lazyHiddenWindow
) {
5647 rv
= appStartup
->CreateHiddenWindow();
5648 NS_ENSURE_SUCCESS(rv
, NS_ERROR_FAILURE
);
5652 Preferences::RegisterCallbackAndCall(
5653 RegisterApplicationRestartChanged
,
5654 PREF_WIN_REGISTER_APPLICATION_RESTART
);
5655 SetupAlteredPrefetchPref();
5656 SetupSkeletonUIPrefs();
5657 # if defined(MOZ_LAUNCHER_PROCESS)
5658 SetupLauncherProcessPref();
5659 # endif // defined(MOZ_LAUNCHER_PROCESS)
5660 # if defined(MOZ_DEFAULT_BROWSER_AGENT)
5661 # if defined(MOZ_BACKGROUNDTASKS)
5662 // The backgroundtask profile is not a browsing profile, let alone the new
5663 // default profile, so don't mirror its properties into the registry.
5664 if (!BackgroundTasks::IsBackgroundTaskMode())
5665 # endif // defined(MOZ_BACKGROUNDTASKS)
5667 Preferences::RegisterCallbackAndCall(
5668 &OnDefaultAgentTelemetryPrefChanged
,
5669 kPrefHealthReportUploadEnabled
);
5670 Preferences::RegisterCallbackAndCall(
5671 &OnDefaultAgentTelemetryPrefChanged
, kPrefDefaultAgentEnabled
);
5673 Preferences::RegisterCallbackAndCall(
5674 &OnDefaultAgentRemoteSettingsPrefChanged
,
5675 kPrefServicesSettingsServer
);
5677 Preferences::RegisterCallbackAndCall(
5678 &OnSetDefaultBrowserUserChoicePrefChanged
,
5679 kPrefSetDefaultBrowserUserChoicePref
);
5681 SetDefaultAgentLastRunTime();
5683 # endif // defined(MOZ_DEFAULT_BROWSER_AGENT)
5686 #if defined(MOZ_WIDGET_GTK)
5687 // Clear the environment variables so they won't be inherited by child
5688 // processes and confuse things.
5689 for (const auto& name
: kStartupTokenNames
) {
5690 g_unsetenv(name
.get());
5697 // we re-initialize the command-line service and do appleevents munging
5698 // after we are sure that we're not restarting
5699 cmdLine
= new nsCommandLine();
5701 char** tempArgv
= static_cast<char**>(malloc(gArgc
* sizeof(char*)));
5702 for (int i
= 0; i
< gArgc
; i
++) {
5703 tempArgv
[i
] = strdup(gArgv
[i
]);
5705 CommandLineServiceMac::SetupMacCommandLine(gArgc
, tempArgv
, false);
5706 rv
= cmdLine
->Init(gArgc
, tempArgv
, workingDir
,
5707 nsICommandLine::STATE_INITIAL_LAUNCH
);
5709 NS_ENSURE_SUCCESS(rv
, NS_ERROR_FAILURE
);
5711 # ifdef MOZILLA_OFFICIAL
5712 // Check if we're running from a DMG or an app translocated location and
5713 // allow the user to install to the Applications directory.
5714 if (MacRunFromDmgUtils::MaybeInstallAndRelaunch()) {
5715 bool userAllowedQuit
= true;
5716 appStartup
->Quit(nsIAppStartup::eForceQuit
, 0, &userAllowedQuit
);
5721 nsCOMPtr
<nsIObserverService
> obsService
=
5722 mozilla::services::GetObserverService();
5724 obsService
->NotifyObservers(nullptr, "final-ui-startup", nullptr);
5726 (void)appStartup
->DoneStartingUp();
5728 CrashReporter::RecordAnnotationBool(
5729 CrashReporter::Annotation::StartupCrash
, false);
5731 AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed
);
5734 if (!AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed
)) {
5735 rv
= cmdLine
->Run();
5736 NS_ENSURE_SUCCESS_LOG(rv
, NS_ERROR_FAILURE
);
5739 if (!AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed
)) {
5740 #if defined(MOZ_HAS_REMOTE)
5741 // if we have X remote support, start listening for requests on the
5743 if (gRemoteService
) {
5744 gRemoteService
->StartupServer();
5745 gRemoteService
->UnlockStartup();
5747 #endif /* MOZ_WIDGET_GTK */
5749 mNativeApp
->Enable();
5752 #ifdef MOZ_INSTRUMENT_EVENT_LOOP
5753 if (PR_GetEnv("MOZ_INSTRUMENT_EVENT_LOOP")) {
5754 bool logToConsole
= true;
5755 mozilla::InitEventTracing(logToConsole
);
5757 #endif /* MOZ_INSTRUMENT_EVENT_LOOP */
5759 // Send Telemetry about Gecko version and buildid
5760 mozilla::glean::gecko::version
.Set(nsDependentCString(gAppData
->version
));
5761 mozilla::glean::gecko::build_id
.Set(nsDependentCString(gAppData
->buildID
));
5763 #if defined(MOZ_SANDBOX) && defined(XP_LINUX)
5764 // If we're on Linux, we now have information about the OS capabilities
5766 SandboxInfo sandboxInfo
= SandboxInfo::Get();
5767 Telemetry::Accumulate(Telemetry::SANDBOX_HAS_USER_NAMESPACES
,
5768 sandboxInfo
.Test(SandboxInfo::kHasUserNamespaces
));
5770 CrashReporter::RecordAnnotationU32(
5771 CrashReporter::Annotation::ContentSandboxCapabilities
,
5772 sandboxInfo
.AsInteger());
5773 #endif /* MOZ_SANDBOX && XP_LINUX */
5776 LauncherResult
<bool> isAdminWithoutUac
= IsAdminWithoutUac();
5777 if (isAdminWithoutUac
.isOk()) {
5778 Telemetry::ScalarSet(
5779 Telemetry::ScalarID::OS_ENVIRONMENT_IS_ADMIN_WITHOUT_UAC
,
5780 isAdminWithoutUac
.unwrap());
5784 #if defined(MOZ_SANDBOX)
5785 AddSandboxAnnotations();
5786 #endif /* MOZ_SANDBOX */
5788 mProfileSvc
->CompleteStartup();
5791 #ifdef MOZ_BACKGROUNDTASKS
5792 if (BackgroundTasks::IsBackgroundTaskMode()) {
5793 // In background task mode, we don't fire various delayed initialization
5794 // notifications, which in the regular browser is how startup crash tracking
5795 // is marked as finished. Here, getting this far means we don't have a
5797 rv
= appStartup
->TrackStartupCrashEnd();
5798 NS_ENSURE_SUCCESS(rv
, rv
);
5800 // We never open a window, but don't want to exit immediately.
5801 rv
= appStartup
->EnterLastWindowClosingSurvivalArea();
5802 NS_ENSURE_SUCCESS(rv
, rv
);
5804 // Avoid some small differences in initialization order across platforms.
5805 nsCOMPtr
<nsIPowerManagerService
> powerManagerService
=
5806 do_GetService(POWERMANAGERSERVICE_CONTRACTID
);
5807 nsCOMPtr
<nsIStringBundleService
> stringBundleService
=
5808 do_GetService(NS_STRINGBUNDLE_CONTRACTID
);
5810 rv
= BackgroundTasks::RunBackgroundTask(cmdLine
);
5811 NS_ENSURE_SUCCESS(rv
, rv
);
5816 rv
= appStartup
->Run();
5817 if (NS_FAILED(rv
)) {
5818 NS_ERROR("failed to run appstartup");
5819 gLogConsoleErrors
= true;
5826 #if defined(MOZ_WIDGET_ANDROID)
5827 static already_AddRefed
<nsIFile
> GreOmniPath(int argc
, char** argv
) {
5830 const char* path
= nullptr;
5831 ArgResult ar
= CheckArg(argc
, argv
, "greomni", &path
, CheckArgFlag::None
);
5832 if (ar
== ARG_BAD
) {
5833 PR_fprintf(PR_STDERR
,
5834 "Error: argument --greomni requires a path argument\n");
5838 if (!path
) return nullptr;
5840 nsCOMPtr
<nsIFile
> greOmni
;
5841 rv
= XRE_GetFileFromPath(path
, getter_AddRefs(greOmni
));
5842 if (NS_FAILED(rv
)) {
5843 PR_fprintf(PR_STDERR
, "Error: argument --greomni requires a valid path\n");
5847 return greOmni
.forget();
5852 * XRE_main - A class based main entry point used by most platforms.
5853 * Note that on OSX, aAppData->xreDirectory will point to
5854 * .app/Contents/Resources.
5856 int XREMain::XRE_main(int argc
, char* argv
[], const BootstrapConfig
& aConfig
) {
5862 mozilla::LogModule::Init(gArgc
, gArgv
);
5865 NS_SetCurrentThreadName("MainThread");
5868 AUTO_BASE_PROFILER_LABEL("XREMain::XRE_main (around Gecko Profiler)", OTHER
);
5870 AUTO_PROFILER_LABEL("XREMain::XRE_main", OTHER
);
5873 // We call this early because it will kick off a background-thread task
5874 // to register the fonts, and we'd like it to have a chance to complete
5875 // before gfxPlatform initialization actually requires it.
5876 gfxPlatformMac::RegisterSupplementalFonts();
5879 #ifdef MOZ_CODE_COVERAGE
5880 CodeCoverageHandler::Init();
5883 nsresult rv
= NS_OK
;
5885 if (aConfig
.appData
) {
5886 mAppData
= MakeUnique
<XREAppData
>(*aConfig
.appData
);
5888 MOZ_RELEASE_ASSERT(aConfig
.appDataPath
);
5889 nsCOMPtr
<nsIFile
> appini
;
5890 rv
= XRE_GetFileFromPath(aConfig
.appDataPath
, getter_AddRefs(appini
));
5891 if (NS_FAILED(rv
)) {
5892 Output(true, "Error: unrecognized path: %s\n", aConfig
.appDataPath
);
5896 mAppData
= MakeUnique
<XREAppData
>();
5897 rv
= XRE_ParseAppData(appini
, *mAppData
);
5898 if (NS_FAILED(rv
)) {
5899 Output(true, "Couldn't read application.ini");
5903 appini
->GetParent(getter_AddRefs(mAppData
->directory
));
5906 const char* appRemotingName
= getenv("MOZ_APP_REMOTINGNAME");
5907 if (appRemotingName
) {
5908 mAppData
->remotingName
= appRemotingName
;
5909 } else if (!mAppData
->remotingName
) {
5910 mAppData
->remotingName
= mAppData
->name
;
5912 // used throughout this file
5913 gAppData
= mAppData
.get();
5915 nsCOMPtr
<nsIFile
> binFile
;
5916 rv
= XRE_GetBinaryPath(getter_AddRefs(binFile
));
5917 NS_ENSURE_SUCCESS(rv
, 1);
5919 rv
= binFile
->GetPath(gAbsoluteArgv0Path
);
5920 NS_ENSURE_SUCCESS(rv
, 1);
5922 if (!mAppData
->xreDirectory
) {
5923 nsCOMPtr
<nsIFile
> greDir
;
5925 #if defined(MOZ_WIDGET_ANDROID)
5926 greDir
= GreOmniPath(argc
, argv
);
5931 rv
= binFile
->GetParent(getter_AddRefs(greDir
));
5932 if (NS_FAILED(rv
)) return 2;
5936 nsCOMPtr
<nsIFile
> parent
;
5937 greDir
->GetParent(getter_AddRefs(parent
));
5938 greDir
= parent
.forget();
5939 greDir
->AppendNative("Resources"_ns
);
5942 mAppData
->xreDirectory
= greDir
;
5945 #if defined(MOZ_WIDGET_ANDROID)
5946 nsCOMPtr
<nsIFile
> dataDir
;
5947 rv
= binFile
->GetParent(getter_AddRefs(dataDir
));
5948 if (NS_FAILED(rv
)) return 2;
5950 mAppData
->directory
= dataDir
;
5952 if (aConfig
.appData
&& aConfig
.appDataPath
) {
5953 mAppData
->xreDirectory
->Clone(getter_AddRefs(mAppData
->directory
));
5954 mAppData
->directory
->AppendNative(nsDependentCString(aConfig
.appDataPath
));
5958 if (!mAppData
->directory
) {
5959 mAppData
->directory
= mAppData
->xreDirectory
;
5963 # if defined(MOZ_SANDBOX)
5964 mAppData
->sandboxBrokerServices
= aConfig
.sandboxBrokerServices
;
5965 # endif // defined(MOZ_SANDBOX)
5968 DebugOnly
<bool> result
= WindowsBCryptInitialization();
5972 # if defined(_M_IX86) || defined(_M_X64)
5974 DebugOnly
<bool> result
= WindowsMsctfInitialization();
5977 # endif // _M_IX86 || _M_X64
5979 #endif // defined(XP_WIN)
5981 // Once we unset the exception handler, we lose the ability to properly
5982 // detect hangs -- they show up as crashes. We do this as late as possible.
5983 // In particular, after ProcessRuntime is destroyed on Windows.
5984 auto unsetExceptionHandler
= MakeScopeExit([&] {
5985 if (mAppData
->flags
& NS_XRE_ENABLE_CRASH_REPORTER
)
5986 return CrashReporter::UnsetExceptionHandler();
5990 mozilla::AutoIOInterposer ioInterposerGuard
;
5991 ioInterposerGuard
.Init();
5994 // We should have already done this when we created the skeleton UI. However,
5995 // there is code in here which needs xul in order to work, like EnsureMTA. It
5996 // should be setup that running it again is safe.
5997 mozilla::mscom::ProcessRuntime msCOMRuntime
;
6002 int result
= XRE_mainInit(&exit
);
6003 if (result
!= 0 || exit
) return result
;
6005 // If we exit gracefully, remove the startup crash canary file.
6006 auto cleanup
= MakeScopeExit([&]() -> nsresult
{
6008 nsCOMPtr
<nsIFile
> crashFile
;
6009 MOZ_TRY_VAR(crashFile
, GetIncompleteStartupFile(mProfLD
));
6010 crashFile
->Remove(false);
6016 result
= XRE_mainStartup(&exit
);
6017 if (result
!= 0 || exit
) return result
;
6019 // Start the real application. We use |aInitJSContext = false| because
6020 // XRE_mainRun wants to initialize the JSContext after reading user prefs.
6022 mScopedXPCOM
= MakeUnique
<ScopedXPCOMStartup
>();
6024 rv
= mScopedXPCOM
->Initialize(/* aInitJSContext = */ false);
6025 if (rv
== NS_ERROR_OMNIJAR_CORRUPT
) {
6026 if (XRE_IsParentProcess()
6027 #ifdef MOZ_BACKGROUNDTASKS
6028 && !mozilla::BackgroundTasks::IsBackgroundTaskMode()
6033 "The installation seems to be corrupt.\nPlease check your hardware "
6034 "and disk setup\nand/or re-install.\n");
6036 MOZ_CRASH("NS_ERROR_OMNIJAR_CORRUPT");
6038 NS_ENSURE_SUCCESS(rv
, 1);
6042 if (rv
== NS_ERROR_OMNIJAR_OR_DIR_MISSING
) {
6043 if (XRE_IsParentProcess()
6044 #ifdef MOZ_BACKGROUNDTASKS
6045 && !mozilla::BackgroundTasks::IsBackgroundTaskMode()
6049 "The installation seems to be incomplete.\nPlease check your "
6050 "hardware and disk setup\nand/or re-install.\n");
6052 if (mozilla::IsPackagedBuild()) {
6053 // IsPackagedBuild just looks for omni.ja on disk. If we were able to
6054 // find and open it before but not to load the expected JS module from
6055 // it now, signal corruption.
6056 MOZ_CRASH("NS_ERROR_OMNIJAR_CORRUPT");
6058 MOZ_CRASH("NS_ERROR_OMNIJAR_OR_DIR_MISSING");
6062 XRE_CleanupX11ErrorHandler();
6065 #ifdef MOZ_INSTRUMENT_EVENT_LOOP
6066 mozilla::ShutdownEventTracing();
6069 gAbsoluteArgv0Path
.Truncate();
6071 #if defined(MOZ_HAS_REMOTE)
6072 // Shut down the remote service. We must do this before calling LaunchChild
6073 // if we're restarting because otherwise the new instance will attempt to
6074 // remote to this instance.
6075 if (gRemoteService
) {
6076 gRemoteService
->ShutdownServer();
6077 gRemoteService
= nullptr;
6079 #endif /* MOZ_WIDGET_GTK */
6081 mScopedXPCOM
= nullptr;
6083 // unlock the profile after ScopedXPCOMStartup object (xpcom)
6084 // has gone out of scope. see bug #386739 for more details
6085 mProfileLock
->Unlock();
6086 gProfileLock
= nullptr;
6088 gLastAppVersion
.Truncate();
6089 gLastAppBuildID
.Truncate();
6091 #ifdef MOZ_WIDGET_GTK
6092 // gdk_display_close also calls gdk_display_manager_set_default_display
6093 // appropriately when necessary.
6094 if (!gfxPlatform::IsHeadless()) {
6096 WaylandDisplayRelease();
6097 gWaylandProxy
= nullptr;
6102 mozilla::AppShutdown::MaybeDoRestart();
6104 XRE_DeinitCommandLine();
6106 if (NS_FAILED(rv
)) {
6109 return mozilla::AppShutdown::GetExitCode();
6112 void XRE_StopLateWriteChecks(void) { mozilla::StopLateWriteChecks(); }
6114 int XRE_main(int argc
, char* argv
[], const BootstrapConfig
& aConfig
) {
6117 int result
= main
.XRE_main(argc
, argv
, aConfig
);
6118 mozilla::RecordShutdownEndTimeStamp();
6119 #ifdef MOZ_BACKGROUNDTASKS
6120 // This is well after the profile has been unlocked, so it's okay if this does
6121 // delete this background task's temporary profile.
6122 mozilla::BackgroundTasks::Shutdown();
6127 nsresult
XRE_InitCommandLine(int aArgc
, char* aArgv
[]) {
6128 nsresult rv
= NS_OK
;
6131 CommandLine::Init(aArgc
, aArgv
);
6134 // these leak on error, but that's OK: we'll just exit()
6135 char** canonArgs
= new char*[aArgc
];
6137 // get the canonical version of the binary's path
6138 nsCOMPtr
<nsIFile
> binFile
;
6139 rv
= XRE_GetBinaryPath(getter_AddRefs(binFile
));
6140 if (NS_FAILED(rv
)) return NS_ERROR_FAILURE
;
6142 nsAutoCString canonBinPath
;
6143 rv
= binFile
->GetNativePath(canonBinPath
);
6144 if (NS_FAILED(rv
)) return NS_ERROR_FAILURE
;
6146 canonArgs
[0] = strdup(canonBinPath
.get());
6148 for (int i
= 1; i
< aArgc
; ++i
) {
6150 canonArgs
[i
] = strdup(aArgv
[i
]);
6154 NS_ASSERTION(!CommandLine::IsInitialized(), "Bad news!");
6155 CommandLine::Init(aArgc
, canonArgs
);
6157 for (int i
= 0; i
< aArgc
; ++i
) free(canonArgs
[i
]);
6161 #if defined(MOZ_WIDGET_ANDROID)
6162 // gAppData is non-null iff this is the parent process. Otherwise,
6163 // the `-greomni`/`-appomni` flags are cross-platform and handled in
6164 // ContentProcess::Init.
6166 nsCOMPtr
<nsIFile
> greOmni
= gAppData
->xreDirectory
;
6168 return NS_ERROR_FAILURE
;
6170 mozilla::Omnijar::Init(greOmni
, greOmni
);
6177 nsresult
XRE_DeinitCommandLine() {
6178 nsresult rv
= NS_OK
;
6180 CommandLine::Terminate();
6185 GeckoProcessType
XRE_GetProcessType() { return GetGeckoProcessType(); }
6187 const char* XRE_GetProcessTypeString() {
6188 return XRE_GeckoProcessTypeToString(XRE_GetProcessType());
6191 GeckoChildID
XRE_GetChildID() { return GetGeckoChildID(); }
6193 bool XRE_IsE10sParentProcess() {
6194 #ifdef MOZ_WIDGET_ANDROID
6195 return XRE_IsParentProcess() && BrowserTabsRemoteAutostart() &&
6196 mozilla::jni::IsAvailable();
6198 return XRE_IsParentProcess() && BrowserTabsRemoteAutostart();
6202 #define GECKO_PROCESS_TYPE(enum_value, enum_name, string_name, proc_typename, \
6203 process_bin_type, procinfo_typename, \
6204 webidl_typename, allcaps_name) \
6205 bool XRE_Is##proc_typename##Process() { \
6206 return XRE_GetProcessType() == GeckoProcessType_##enum_name; \
6208 #include "mozilla/GeckoProcessTypes.h"
6209 #undef GECKO_PROCESS_TYPE
6211 bool XRE_UseNativeEventProcessing() {
6212 switch (XRE_GetProcessType()) {
6213 #if defined(XP_MACOSX) || defined(XP_WIN)
6214 case GeckoProcessType_RDD
:
6215 case GeckoProcessType_Socket
:
6217 case GeckoProcessType_Utility
: {
6218 # if defined(XP_WIN)
6219 auto upc
= mozilla::ipc::UtilityProcessChild::Get();
6222 using SboxKind
= mozilla::ipc::SandboxingKind
;
6223 // These processes are used as external hosts for accessing Windows
6224 // APIs which (may) require a Windows native event loop.
6225 return upc
->mSandbox
== SboxKind::WINDOWS_UTILS
||
6226 upc
->mSandbox
== SboxKind::WINDOWS_FILE_DIALOG
;
6229 # endif // defined(XP_WIN)
6231 #endif // defined(XP_MACOSX) || defined(XP_WIN)
6232 case GeckoProcessType_GMPlugin
:
6233 return mozilla::gmp::GMPProcessChild::UseNativeEventProcessing();
6234 case GeckoProcessType_Content
:
6235 return StaticPrefs::dom_ipc_useNativeEventProcessing_content();
6243 uint32_t GetMaxWebProcessCount() {
6244 // multiOptOut is in int to allow us to run multiple experiments without
6245 // introducing multiple prefs a la the autostart.N prefs.
6246 if (Preferences::GetInt("dom.ipc.multiOptOut", 0) >=
6247 nsIXULRuntime::E10S_MULTI_EXPERIMENT
) {
6251 const char* optInPref
= "dom.ipc.processCount";
6252 uint32_t optInPrefValue
= Preferences::GetInt(optInPref
, 1);
6253 return std::max(1u, optInPrefValue
);
6256 const char* PlatformBuildID() { return gToolkitBuildID
; }
6258 } // namespace mozilla
6260 void SetupErrorHandling(const char* progname
) {
6262 /* On Windows XPSP3 and Windows Vista if DEP is configured off-by-default
6263 we still want DEP protection: enable it explicitly and programmatically.
6265 This function is not available on WinXPSP2 so we dynamically load it.
6268 HMODULE kernel32
= GetModuleHandleW(L
"kernel32.dll");
6269 SetProcessDEPPolicyFunc _SetProcessDEPPolicy
=
6270 (SetProcessDEPPolicyFunc
)GetProcAddress(kernel32
, "SetProcessDEPPolicy");
6271 if (_SetProcessDEPPolicy
) _SetProcessDEPPolicy(PROCESS_DEP_ENABLE
);
6275 // Suppress the "DLL Foo could not be found" dialog, such that if dependent
6276 // libraries (such as GDI+) are not preset, we gracefully fail to load those
6277 // XPCOM components, instead of being ungraceful.
6278 UINT realMode
= SetErrorMode(0);
6279 realMode
|= SEM_FAILCRITICALERRORS
;
6280 // If XRE_NO_WINDOWS_CRASH_DIALOG is set, suppress displaying the "This
6281 // application has crashed" dialog box. This is mainly useful for
6282 // automated testing environments, e.g. tinderbox, where there's no need
6283 // for a dozen of the dialog boxes to litter the console
6284 if (getenv("XRE_NO_WINDOWS_CRASH_DIALOG"))
6285 realMode
|= SEM_NOGPFAULTERRORBOX
| SEM_NOOPENFILEERRORBOX
;
6287 SetErrorMode(realMode
);
6291 InstallSignalHandlers(progname
);
6293 // Unbuffer stdout, needed for tinderbox tests.
6297 static bool gRunSelfAsContentProc
= false;
6299 void XRE_EnableSameExecutableForContentProc() {
6300 if (!PR_GetEnv("MOZ_SEPARATE_CHILD_PROCESS")) {
6301 gRunSelfAsContentProc
= true;
6305 mozilla::BinPathType
XRE_GetChildProcBinPathType(
6306 GeckoProcessType aProcessType
) {
6307 MOZ_ASSERT(aProcessType
!= GeckoProcessType_Default
);
6309 if (!gRunSelfAsContentProc
) {
6310 return BinPathType::PluginContainer
;
6314 // On Windows, plugin-container may or may not be used depending on
6315 // the process type (e.g., actual plugins vs. content processes)
6316 switch (aProcessType
) {
6317 # define GECKO_PROCESS_TYPE(enum_value, enum_name, string_name, \
6318 proc_typename, process_bin_type, \
6319 procinfo_typename, webidl_typename, allcaps_name) \
6320 case GeckoProcessType_##enum_name: \
6321 return BinPathType::process_bin_type;
6322 # include "mozilla/GeckoProcessTypes.h"
6323 # undef GECKO_PROCESS_TYPE
6325 return BinPathType::PluginContainer
;
6328 // On (non-macOS) Unix, plugin-container isn't used (except in cases
6329 // like xpcshell that are handled by the gRunSelfAsContentProc check
6330 // above). It isn't necessary the way it is on other platforms, and
6331 // it interferes with using the fork server.
6332 return BinPathType::Self
;
6336 // From mozglue/static/rust/lib.rs
6337 extern "C" void install_rust_hooks();
6339 struct InstallRustHooks
{
6340 InstallRustHooks() { install_rust_hooks(); }
6343 InstallRustHooks sInstallRustHooks
;
6345 #ifdef MOZ_ASAN_REPORTER
6346 void setASanReporterPath(nsIFile
* aDir
) {
6347 nsCOMPtr
<nsIFile
> dir
;
6348 aDir
->Clone(getter_AddRefs(dir
));
6350 dir
->Append(u
"asan"_ns
);
6351 nsresult rv
= dir
->Create(nsIFile::DIRECTORY_TYPE
, 0700);
6352 if (NS_WARN_IF(NS_FAILED(rv
) && rv
!= NS_ERROR_FILE_ALREADY_EXISTS
)) {
6353 MOZ_CRASH("[ASan Reporter] Unable to create crash directory.");
6356 dir
->Append(u
"ff_asan_log"_ns
);
6359 nsAutoString nspathW
;
6360 rv
= dir
->GetPath(nspathW
);
6361 NS_ConvertUTF16toUTF8
nspath(nspathW
);
6363 nsAutoCString nspath
;
6364 rv
= dir
->GetNativePath(nspath
);
6366 if (NS_FAILED(rv
)) {
6367 MOZ_CRASH("[ASan Reporter] Unable to get native path for crash directory.");
6370 __sanitizer_set_report_path(nspath
.get());