Bug 1900426 - Implement DnD for shadow-crossing selection r=jjaschke,smaug,dom-core
[gecko.git] / toolkit / xre / nsAppRunner.cpp
blob75a8f362bf2b91a7b123aafb468c7d0f48562088
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"
51 #endif
52 #include "ProfileReset.h"
54 #ifdef MOZ_INSTRUMENT_EVENT_LOOP
55 # include "EventTracer.h"
56 #endif
58 #ifdef XP_MACOSX
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>
67 #endif
69 #include "prnetdb.h"
70 #include "prprf.h"
71 #include "prproces.h"
72 #include "prenv.h"
73 #include "prtime.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"
95 #include "nsIURI.h"
96 #include "nsIURL.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"
108 #ifdef XP_MACOSX
109 # include "gfxPlatformMac.h"
110 #endif
112 #include "mozilla/Unused.h"
114 #ifdef XP_WIN
115 # include "nsIWinAppHelper.h"
116 # include <windows.h>
117 # include <intrin.h>
118 # include <math.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"
135 # endif
137 # if defined(MOZ_DEFAULT_BROWSER_AGENT)
138 # include "nsIWindowsRegKey.h"
139 # endif
141 # ifndef PROCESS_DEP_ENABLE
142 # define PROCESS_DEP_ENABLE 0x1
143 # endif
144 #endif
146 #if defined(MOZ_SANDBOX)
147 # include "mozilla/SandboxSettings.h"
148 #endif
150 #ifdef ACCESSIBILITY
151 # include "nsAccessibilityService.h"
152 # if defined(XP_WIN)
153 # include "mozilla/a11y/Compatibility.h"
154 # include "mozilla/a11y/Platform.h"
155 # endif
156 #endif
158 #include "nsCRT.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"
166 #include "nsXPCOM.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"
181 #include <stdlib.h>
182 #include <locale.h>
184 #ifdef XP_UNIX
185 # include <errno.h>
186 # include <pwd.h>
187 # include <string.h>
188 # include <sys/resource.h>
189 # include <sys/stat.h>
190 # include <unistd.h>
191 #endif
193 #ifdef XP_WIN
194 # include <process.h>
195 # include <shlobj.h>
196 # include "mozilla/WinDllServices.h"
197 # include "nsThreadUtils.h"
198 # include "WinUtils.h"
199 #endif
201 #ifdef XP_MACOSX
202 # include "nsILocalFileMac.h"
203 # include "nsCommandLineServiceMac.h"
204 #endif
206 // for X remote support
207 #if defined(MOZ_HAS_REMOTE)
208 # include "nsRemoteService.h"
209 #endif
211 #if defined(DEBUG) && defined(XP_WIN)
212 # include <malloc.h>
213 #endif
215 #if defined(XP_MACOSX)
216 # include <Carbon/Carbon.h>
217 #endif
219 #ifdef DEBUG
220 # include "mozilla/Logging.h"
221 #endif
223 #ifdef MOZ_JPROF
224 # include "jprof.h"
225 #endif
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"
233 #endif
235 #include "base/command_line.h"
236 #include "GTestRunner.h"
238 #ifdef MOZ_WIDGET_ANDROID
239 # include "mozilla/java/GeckoAppShellWrappers.h"
240 #endif
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"
247 # endif
248 #endif
250 #ifdef MOZ_CODE_COVERAGE
251 # include "mozilla/CodeCoverageHandler.h"
252 #endif
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"
261 #endif
263 #ifdef USE_GLX_TEST
264 # include "mozilla/GUniquePtr.h"
265 # include "mozilla/GfxInfo.h"
266 #endif
268 #ifdef MOZ_WIDGET_GTK
269 # include "nsAppShell.h"
270 #endif
271 #ifdef MOZ_ENABLE_DBUS
272 # include "DBusService.h"
273 #endif
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)
296 #if defined(XP_WIN)
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,
308 #endif
310 int gArgc;
311 char** gArgv;
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;
321 #endif
323 int gRestartArgc;
324 char** gRestartArgv;
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;
338 #if defined(XP_WIN)
339 nsString gProcessStartupShortcut;
340 #endif
342 #if defined(MOZ_WIDGET_GTK)
343 # include <glib.h>
344 # include "mozilla/WidgetUtilsGtk.h"
345 # include <gtk/gtk.h>
346 # ifdef MOZ_WAYLAND
347 # include <gdk/gdkwayland.h>
348 # include "mozilla/widget/nsWaylandDisplay.h"
349 # include "wayland-proxy.h"
350 # endif
351 # ifdef MOZ_X11
352 # include <gdk/gdkx.h>
353 # endif /* MOZ_X11 */
354 #endif
356 #if defined(MOZ_WAYLAND)
357 std::unique_ptr<WaylandProxy> gWaylandProxy;
358 #endif
360 #include "BinaryPath.h"
362 #ifdef MOZ_LOGGING
363 # include "mozilla/Logging.h"
364 extern mozilla::LazyLogModule gWidgetWaylandLog;
365 #endif /* MOZ_LOGGING */
367 #ifdef FUZZING
368 # include "FuzzerRunner.h"
370 namespace mozilla {
371 FuzzerRunner* fuzzerRunner = 0;
372 } // namespace mozilla
374 # ifdef LIBFUZZER
375 void XRE_LibFuzzerSetDriver(LibFuzzerDriver aDriver) {
376 mozilla::fuzzerRunner->setParams(aDriver);
378 # endif
379 #endif // FUZZING
381 // Undo X11/X.h's definition of None
382 #undef None
384 namespace mozilla {
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) {
403 char* expr =
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) {
411 #ifdef XP_WIN
412 nsAutoString path;
413 file->GetPath(path);
414 SetEnvironmentVariableW(NS_ConvertASCIItoUTF16(name).get(), path.get());
415 #else
416 nsAutoCString path;
417 file->GetNativePath(path);
418 SaveWordToEnv(name, path);
419 #endif
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) {
444 return false;
446 if (!PR_GetEnv("DISPLAY")) {
447 // No X11 display, so try to run wayland.
448 return true;
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)) {
456 NS_WARNING(
457 "Wayland backend should be enabled by MOZ_ENABLE_WAYLAND=1."
458 "GDK_BACKEND is a Gtk3 debug variable and may cause issues.");
459 return true;
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);
469 }();
470 return isWaylandEnabled;
472 #else
473 bool IsWaylandEnabled() { return false; }
474 #endif
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.
480 * @param isError
481 * Pass true to indicate severe errors.
482 * @param fmt
483 * printf-style format string followed by arguments.
485 static MOZ_FORMAT_PRINTF(2, 3) void Output(bool isError, const char* fmt, ...) {
486 va_list ap;
487 va_start(ap, fmt);
489 #if defined(XP_WIN) && !MOZ_WINCONSOLE
490 SmprintfPointer msg = mozilla::Vsmprintf(fmt, ap);
491 if (msg) {
492 UINT flags = MB_OK;
493 if (isError)
494 flags |= MB_ICONERROR;
495 else
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);
509 if (msg) {
510 __android_log_print(isError ? ANDROID_LOG_ERROR : ANDROID_LOG_INFO,
511 "GeckoRuntime", "%s", msg.get());
513 #else
514 vfprintf(stderr, fmt, ap);
515 #endif
517 va_end(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;
550 enum E10sStatus {
551 kE10sEnabledByDefault,
552 kE10sForceDisabled,
555 static bool gBrowserTabsRemoteAutostart = false;
556 static E10sStatus gBrowserTabsRemoteStatus;
557 static bool gBrowserTabsRemoteAutostartInitialized = false;
559 namespace mozilla {
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();
582 #else
583 bool allowDisablingE10s = true;
584 #endif
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
604 // upon startup.
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;
619 #ifdef XP_WIN
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
627 // Enrolled
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
638 // disqualify you
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
643 // of gWin32kStatus.
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
647 // browser start
648 // [G] While enrolled, becoming TemporaryRequirement will _not_ disqualify you,
649 // but the session status will prevent win32k lockdown from taking effect.
651 // The win32k pref
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";
671 namespace mozilla {
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 ||
685 aStatus ==
686 nsIXULRuntime::ContentWin32kLockdownState::MissingWebRender ||
687 aStatus ==
688 nsIXULRuntime::ContentWin32kLockdownState::MissingRemoteWebGL ||
689 aStatus ==
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) {
700 auto newStatusInt =
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);
711 namespace {
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 {
716 public:
717 NS_DECL_ISUPPORTS
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,
723 nullptr);
724 return NS_OK;
727 private:
728 ~Win32kEnrollmentStatusShutdownObserver() = default;
730 NS_IMPL_ISUPPORTS(Win32kEnrollmentStatusShutdownObserver, nsIObserver)
731 } // namespace
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();
741 #endif // XP_WIN
743 namespace mozilla {
744 void EnsureWin32kInitialized();
747 nsIXULRuntime::ContentWin32kLockdownState GetLiveWin32kLockdownState() {
748 #ifdef XP_WIN
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;
758 # endif
760 mozilla::EnsureWin32kInitialized();
761 gfxPlatform::GetPlatform();
763 if (gSafeMode) {
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;
808 bool prefSetByUser =
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);
815 if (prefSetByUser) {
816 if (prefValue) {
817 return nsIXULRuntime::ContentWin32kLockdownState::EnabledByUserPref;
818 } else {
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;
831 if (defaultValue) {
832 return nsIXULRuntime::ContentWin32kLockdownState::EnabledByDefault;
833 } else {
834 return nsIXULRuntime::ContentWin32kLockdownState::DisabledByDefault;
837 #else
839 return nsIXULRuntime::ContentWin32kLockdownState::OperatingSystemNotSupported;
841 #endif
844 namespace mozilla {
846 void EnsureWin32kInitialized() {
847 if (gWin32kInitialized) {
848 return;
850 gWin32kInitialized = true;
852 #ifdef XP_WIN
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
857 // safemode session.
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",
875 false);
878 // If the user no longer qualifies because they edited a required pref, check
879 // that. [B] [E]
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);
900 // Set the state
901 gWin32kStatus = GetLiveWin32kLockdownState();
903 #else
904 gWin32kStatus =
905 nsIXULRuntime::ContentWin32kLockdownState::OperatingSystemNotSupported;
906 gWin32kExperimentStatus = nsIXULRuntime::eExperimentStatusUnenrolled;
908 #endif // XP_WIN
911 nsIXULRuntime::ContentWin32kLockdownState GetWin32kLockdownState() {
912 #ifdef XP_WIN
914 mozilla::EnsureWin32kInitialized();
915 return gWin32kStatus;
917 #else
919 return nsIXULRuntime::ContentWin32kLockdownState::OperatingSystemNotSupported;
921 #endif
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) {
960 return;
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);
968 return;
971 if (!BrowserTabsRemoteAutostart()) {
972 gFissionAutostart = false;
973 if (gBrowserTabsRemoteStatus == kE10sForceDisabled) {
974 gFissionDecisionStatus = nsIXULRuntime::eFissionDisabledByE10sEnv;
975 } else {
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;
984 } else {
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;
992 } else {
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);
1011 namespace mozilla {
1013 bool FissionAutostart() {
1014 EnsureFissionAutostartInitialized();
1015 return gFissionAutostart;
1018 } // namespace mozilla
1020 // End Fission Infrastructure =========================================
1022 namespace mozilla {
1024 bool SessionHistoryInParent() {
1025 return FissionAutostart() ||
1026 !StaticPrefs::
1027 fission_disableSessionHistoryInParent_AtStartup_DoNotUseDirectly();
1030 bool SessionStorePlatformCollection() {
1031 return SessionHistoryInParent() &&
1032 !StaticPrefs::
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
1045 * singleton.
1047 class nsXULAppInfo : public nsIXULAppInfo,
1048 #ifdef XP_WIN
1049 public nsIWinAppHelper,
1050 #endif
1051 public nsICrashReporter,
1052 public nsIFinishDumpingCallback,
1053 public nsIXULRuntime
1056 public:
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
1064 #ifdef XP_WIN
1065 NS_DECL_NSIWINAPPHELPER
1066 #endif
1069 NS_INTERFACE_MAP_BEGIN(nsXULAppInfo)
1070 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXULRuntime)
1071 NS_INTERFACE_MAP_ENTRY(nsIXULRuntime)
1072 #ifdef XP_WIN
1073 NS_INTERFACE_MAP_ENTRY(nsIWinAppHelper)
1074 #endif
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; }
1088 NS_IMETHODIMP
1089 nsXULAppInfo::GetVendor(nsACString& aResult) {
1090 if (XRE_IsContentProcess()) {
1091 ContentChild* cc = ContentChild::GetSingleton();
1092 aResult = cc->GetAppInfo().vendor;
1093 return NS_OK;
1095 aResult.Assign(gAppData->vendor);
1097 return NS_OK;
1100 NS_IMETHODIMP
1101 nsXULAppInfo::GetName(nsACString& aResult) {
1102 if (XRE_IsContentProcess()) {
1103 ContentChild* cc = ContentChild::GetSingleton();
1104 aResult = cc->GetAppInfo().name;
1105 return NS_OK;
1108 #ifdef MOZ_WIDGET_ANDROID
1109 nsCString name = java::GeckoAppShell::GetAppName()->ToCString();
1110 aResult.Assign(std::move(name));
1111 #else
1112 aResult.Assign(gAppData->name);
1113 #endif
1115 return NS_OK;
1118 NS_IMETHODIMP
1119 nsXULAppInfo::GetID(nsACString& aResult) {
1120 if (XRE_IsContentProcess()) {
1121 ContentChild* cc = ContentChild::GetSingleton();
1122 aResult = cc->GetAppInfo().ID;
1123 return NS_OK;
1125 aResult.Assign(gAppData->ID);
1127 return NS_OK;
1130 NS_IMETHODIMP
1131 nsXULAppInfo::GetVersion(nsACString& aResult) {
1132 if (XRE_IsContentProcess()) {
1133 ContentChild* cc = ContentChild::GetSingleton();
1134 aResult = cc->GetAppInfo().version;
1135 return NS_OK;
1137 aResult.Assign(gAppData->version);
1139 return NS_OK;
1142 NS_IMETHODIMP
1143 nsXULAppInfo::GetPlatformVersion(nsACString& aResult) {
1144 aResult.Assign(gToolkitVersion);
1146 return NS_OK;
1149 NS_IMETHODIMP
1150 nsXULAppInfo::GetAppBuildID(nsACString& aResult) {
1151 if (XRE_IsContentProcess()) {
1152 ContentChild* cc = ContentChild::GetSingleton();
1153 aResult = cc->GetAppInfo().buildID;
1154 return NS_OK;
1156 aResult.Assign(gAppData->buildID);
1158 return NS_OK;
1161 NS_IMETHODIMP
1162 nsXULAppInfo::GetPlatformBuildID(nsACString& aResult) {
1163 aResult.Assign(gToolkitBuildID);
1165 return NS_OK;
1168 NS_IMETHODIMP
1169 nsXULAppInfo::GetUAName(nsACString& aResult) {
1170 if (XRE_IsContentProcess()) {
1171 ContentChild* cc = ContentChild::GetSingleton();
1172 aResult = cc->GetAppInfo().UAName;
1173 return NS_OK;
1175 aResult.Assign(gAppData->UAName);
1177 return NS_OK;
1180 NS_IMETHODIMP
1181 nsXULAppInfo::GetSourceURL(nsACString& aResult) {
1182 if (XRE_IsContentProcess()) {
1183 ContentChild* cc = ContentChild::GetSingleton();
1184 aResult = cc->GetAppInfo().sourceURL;
1185 return NS_OK;
1187 aResult.Assign(gAppData->sourceURL);
1189 return NS_OK;
1192 NS_IMETHODIMP
1193 nsXULAppInfo::GetUpdateURL(nsACString& aResult) {
1194 if (XRE_IsContentProcess()) {
1195 ContentChild* cc = ContentChild::GetSingleton();
1196 aResult = cc->GetAppInfo().updateURL;
1197 return NS_OK;
1199 aResult.Assign(gAppData->updateURL);
1201 return NS_OK;
1204 NS_IMETHODIMP
1205 nsXULAppInfo::GetLogConsoleErrors(bool* aResult) {
1206 *aResult = gLogConsoleErrors;
1207 return NS_OK;
1210 NS_IMETHODIMP
1211 nsXULAppInfo::SetLogConsoleErrors(bool aValue) {
1212 gLogConsoleErrors = aValue;
1213 return NS_OK;
1216 NS_IMETHODIMP
1217 nsXULAppInfo::GetInSafeMode(bool* aResult) {
1218 *aResult = gSafeMode;
1219 return NS_OK;
1222 NS_IMETHODIMP
1223 nsXULAppInfo::GetOS(nsACString& aResult) {
1224 aResult.AssignLiteral(OS_TARGET);
1225 return NS_OK;
1228 NS_IMETHODIMP
1229 nsXULAppInfo::GetXPCOMABI(nsACString& aResult) {
1230 #ifdef TARGET_XPCOM_ABI
1231 aResult.AssignLiteral(TARGET_XPCOM_ABI);
1232 return NS_OK;
1233 #else
1234 return NS_ERROR_NOT_AVAILABLE;
1235 #endif
1238 NS_IMETHODIMP
1239 nsXULAppInfo::GetWidgetToolkit(nsACString& aResult) {
1240 aResult.AssignLiteral(MOZ_WIDGET_TOOLKIT);
1241 return NS_OK;
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");
1261 NS_IMETHODIMP
1262 nsXULAppInfo::GetProcessType(uint32_t* aResult) {
1263 NS_ENSURE_ARG_POINTER(aResult);
1264 *aResult = XRE_GetProcessType();
1265 return NS_OK;
1268 NS_IMETHODIMP
1269 nsXULAppInfo::GetProcessID(uint32_t* aResult) {
1270 #ifdef XP_WIN
1271 *aResult = GetCurrentProcessId();
1272 #else
1273 *aResult = getpid();
1274 #endif
1275 return NS_OK;
1278 NS_IMETHODIMP
1279 nsXULAppInfo::GetUniqueProcessID(uint64_t* aResult) {
1280 if (XRE_IsContentProcess()) {
1281 ContentChild* cc = ContentChild::GetSingleton();
1282 *aResult = cc->GetID();
1283 } else {
1284 *aResult = 0;
1286 return NS_OK;
1289 NS_IMETHODIMP
1290 nsXULAppInfo::GetRemoteType(nsACString& aRemoteType) {
1291 if (XRE_IsContentProcess()) {
1292 aRemoteType = ContentChild::GetSingleton()->GetRemoteType();
1293 } else {
1294 aRemoteType = NOT_REMOTE_TYPE;
1297 return NS_OK;
1300 static nsCString gLastAppVersion;
1301 static nsCString gLastAppBuildID;
1303 NS_IMETHODIMP
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);
1315 return NS_OK;
1318 NS_IMETHODIMP
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);
1330 return NS_OK;
1333 NS_IMETHODIMP
1334 nsXULAppInfo::GetFissionAutostart(bool* aResult) {
1335 *aResult = FissionAutostart();
1336 return NS_OK;
1339 NS_IMETHODIMP
1340 nsXULAppInfo::GetWin32kExperimentStatus(ExperimentStatus* aResult) {
1341 if (!XRE_IsParentProcess()) {
1342 return NS_ERROR_NOT_AVAILABLE;
1345 EnsureWin32kInitialized();
1346 *aResult = gWin32kExperimentStatus;
1347 return NS_OK;
1350 NS_IMETHODIMP
1351 nsXULAppInfo::GetWin32kLiveStatusTestingOnly(
1352 nsIXULRuntime::ContentWin32kLockdownState* aResult) {
1353 if (!XRE_IsParentProcess()) {
1354 return NS_ERROR_NOT_AVAILABLE;
1357 EnsureWin32kInitialized();
1358 *aResult = GetLiveWin32kLockdownState();
1359 return NS_OK;
1362 NS_IMETHODIMP
1363 nsXULAppInfo::GetWin32kSessionStatus(
1364 nsIXULRuntime::ContentWin32kLockdownState* aResult) {
1365 if (!XRE_IsParentProcess()) {
1366 return NS_ERROR_NOT_AVAILABLE;
1369 EnsureWin32kInitialized();
1370 *aResult = gWin32kStatus;
1371 return NS_OK;
1374 NS_IMETHODIMP
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;
1384 return NS_OK;
1387 NS_IMETHODIMP
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";
1397 break;
1398 case eFissionExperimentTreatment:
1399 aResult = "experimentTreatment";
1400 break;
1401 case eFissionDisabledByE10sEnv:
1402 aResult = "disabledByE10sEnv";
1403 break;
1404 case eFissionEnabledByEnv:
1405 aResult = "enabledByEnv";
1406 break;
1407 case eFissionDisabledByEnv:
1408 aResult = "disabledByEnv";
1409 break;
1410 case eFissionEnabledByDefault:
1411 aResult = "enabledByDefault";
1412 break;
1413 case eFissionDisabledByDefault:
1414 aResult = "disabledByDefault";
1415 break;
1416 case eFissionEnabledByUserPref:
1417 aResult = "enabledByUserPref";
1418 break;
1419 case eFissionDisabledByUserPref:
1420 aResult = "disabledByUserPref";
1421 break;
1422 case eFissionDisabledByE10sOther:
1423 aResult = "disabledByE10sOther";
1424 break;
1425 case eFissionEnabledByRollout:
1426 aResult = "enabledByRollout";
1427 break;
1428 default:
1429 MOZ_ASSERT_UNREACHABLE("Unexpected enum value");
1431 return NS_OK;
1434 NS_IMETHODIMP
1435 nsXULAppInfo::GetSessionHistoryInParent(bool* aResult) {
1436 *aResult = SessionHistoryInParent();
1437 return NS_OK;
1440 NS_IMETHODIMP
1441 nsXULAppInfo::GetSessionStorePlatformCollection(bool* aResult) {
1442 *aResult = SessionStorePlatformCollection();
1443 return NS_OK;
1446 NS_IMETHODIMP
1447 nsXULAppInfo::GetBrowserTabsRemoteAutostart(bool* aResult) {
1448 *aResult = BrowserTabsRemoteAutostart();
1449 return NS_OK;
1452 NS_IMETHODIMP
1453 nsXULAppInfo::GetMaxWebProcessCount(uint32_t* aResult) {
1454 *aResult = mozilla::GetMaxWebProcessCount();
1455 return NS_OK;
1458 NS_IMETHODIMP
1459 nsXULAppInfo::GetAccessibilityEnabled(bool* aResult) {
1460 #ifdef ACCESSIBILITY
1461 *aResult = GetAccService() != nullptr;
1462 #else
1463 *aResult = false;
1464 #endif
1465 return NS_OK;
1468 NS_IMETHODIMP
1469 nsXULAppInfo::GetAccessibilityInstantiator(nsAString& aInstantiator) {
1470 #if defined(ACCESSIBILITY) && defined(XP_WIN)
1471 if (!GetAccService()) {
1472 aInstantiator.Truncate();
1473 return NS_OK;
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);
1487 #else
1488 aInstantiator.Truncate();
1489 #endif
1490 return NS_OK;
1493 NS_IMETHODIMP
1494 nsXULAppInfo::GetIs64Bit(bool* aResult) {
1495 #ifdef HAVE_64BIT_BUILD
1496 *aResult = true;
1497 #else
1498 *aResult = false;
1499 #endif
1500 return NS_OK;
1503 NS_IMETHODIMP
1504 nsXULAppInfo::GetIsTextRecognitionSupported(bool* aResult) {
1505 *aResult = widget::TextRecognition::IsSupported();
1506 return NS_OK;
1509 NS_IMETHODIMP
1510 nsXULAppInfo::InvalidateCachesOnRestart() {
1511 nsCOMPtr<nsIFile> file;
1512 nsresult rv =
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);
1519 nsINIParser parser;
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.
1524 return NS_OK;
1527 nsAutoCString buf;
1528 rv = parser.GetString("Compatibility", "InvalidateCaches", buf);
1530 if (NS_FAILED(rv)) {
1531 PRFileDesc* fd;
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);
1540 PR_Close(fd);
1542 return NS_OK;
1545 NS_IMETHODIMP
1546 nsXULAppInfo::GetReplacedLockTime(PRTime* aReplacedLockTime) {
1547 if (!gProfileLock) return NS_ERROR_NOT_AVAILABLE;
1548 gProfileLock->GetReplacedLockTime(aReplacedLockTime);
1549 return NS_OK;
1552 NS_IMETHODIMP
1553 nsXULAppInfo::GetDefaultUpdateChannel(nsACString& aResult) {
1554 aResult.AssignLiteral(MOZ_STRINGIFY(MOZ_UPDATE_CHANNEL));
1555 return NS_OK;
1558 NS_IMETHODIMP
1559 nsXULAppInfo::GetDistributionID(nsACString& aResult) {
1560 aResult.AssignLiteral(MOZ_DISTRIBUTION_ID);
1561 return NS_OK;
1564 NS_IMETHODIMP
1565 nsXULAppInfo::GetWindowsDLLBlocklistStatus(bool* aResult) {
1566 #if defined(HAS_DLL_BLOCKLIST)
1567 *aResult = DllBlocklist_CheckStatus();
1568 #else
1569 *aResult = false;
1570 #endif
1571 return NS_OK;
1574 NS_IMETHODIMP
1575 nsXULAppInfo::GetRestartedByOS(bool* aResult) {
1576 *aResult = gRestartedByOS;
1577 return NS_OK;
1580 NS_IMETHODIMP
1581 nsXULAppInfo::GetChromeColorSchemeIsDark(bool* aResult) {
1582 PreferenceSheet::EnsureInitialized();
1583 *aResult = PreferenceSheet::ColorSchemeForChrome() == ColorScheme::Dark;
1584 return NS_OK;
1587 NS_IMETHODIMP
1588 nsXULAppInfo::GetContentThemeDerivedColorSchemeIsDark(bool* aResult) {
1589 *aResult =
1590 PreferenceSheet::ThemeDerivedColorSchemeForContent() == ColorScheme::Dark;
1591 return NS_OK;
1594 NS_IMETHODIMP
1595 nsXULAppInfo::GetPrefersReducedMotion(bool* aResult) {
1596 *aResult =
1597 LookAndFeel::GetInt(LookAndFeel::IntID::PrefersReducedMotion, 0) == 1;
1598 return NS_OK;
1601 NS_IMETHODIMP
1602 nsXULAppInfo::GetDrawInTitlebar(bool* aResult) {
1603 *aResult = LookAndFeel::DrawInTitlebar();
1604 return NS_OK;
1607 NS_IMETHODIMP
1608 nsXULAppInfo::GetDesktopEnvironment(nsACString& aDesktopEnvironment) {
1609 #ifdef MOZ_WIDGET_GTK
1610 aDesktopEnvironment.Assign(GetDesktopEnvironmentIdentifier());
1611 #endif
1612 return NS_OK;
1615 NS_IMETHODIMP
1616 nsXULAppInfo::GetIsWayland(bool* aResult) {
1617 #ifdef MOZ_WIDGET_GTK
1618 *aResult = GdkIsWaylandDisplay();
1619 #else
1620 *aResult = false;
1621 #endif
1622 return NS_OK;
1625 NS_IMETHODIMP
1626 nsXULAppInfo::GetProcessStartupShortcut(nsAString& aShortcut) {
1627 #if defined(XP_WIN)
1628 if (XRE_IsParentProcess()) {
1629 aShortcut.Assign(gProcessStartupShortcut);
1630 return NS_OK;
1632 #endif
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)
1643 NS_IMETHODIMP
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());
1653 return NS_OK;
1654 #else
1655 return NS_ERROR_NOT_AVAILABLE;
1656 #endif
1659 #ifdef XP_WIN
1660 NS_IMETHODIMP
1661 nsXULAppInfo::GetUserCanElevate(bool* aUserCanElevate) {
1662 HANDLE rawToken;
1663 if (!::OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY, &rawToken)) {
1664 *aUserCanElevate = false;
1665 return NS_OK;
1668 nsAutoHandle token(rawToken);
1669 LauncherResult<TOKEN_ELEVATION_TYPE> elevationType = GetElevationType(token);
1670 if (elevationType.isErr()) {
1671 *aUserCanElevate = false;
1672 return NS_OK;
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
1683 // elevated)
1684 *aUserCanElevate = (elevationType.inspect() == TokenElevationTypeLimited);
1685 return NS_OK;
1687 #endif
1689 NS_IMETHODIMP
1690 nsXULAppInfo::GetCrashReporterEnabled(bool* aEnabled) {
1691 *aEnabled = CrashReporter::GetEnabled();
1692 return NS_OK;
1695 NS_IMETHODIMP
1696 nsXULAppInfo::SetEnabled(bool aEnabled) {
1697 if (aEnabled) {
1698 if (CrashReporter::GetEnabled()) {
1699 // no point in erroring for double-enabling
1700 return NS_OK;
1703 nsCOMPtr<nsIFile> greBinDir;
1704 NS_GetSpecialDirectory(NS_GRE_BIN_DIR, getter_AddRefs(greBinDir));
1705 if (!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
1719 return NS_OK;
1722 return CrashReporter::UnsetExceptionHandler();
1725 NS_IMETHODIMP
1726 nsXULAppInfo::GetServerURL(nsIURL** aServerURL) {
1727 NS_ENSURE_ARG_POINTER(aServerURL);
1728 if (!CrashReporter::GetEnabled()) return NS_ERROR_NOT_INITIALIZED;
1730 nsAutoCString data;
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);
1742 return NS_OK;
1745 NS_IMETHODIMP
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;
1752 nsAutoCString spec;
1753 nsresult rv = aServerURL->GetSpec(spec);
1754 NS_ENSURE_SUCCESS(rv, rv);
1756 return CrashReporter::SetServerURL(spec);
1759 NS_IMETHODIMP
1760 nsXULAppInfo::GetMinidumpPath(nsIFile** aMinidumpPath) {
1761 if (!CrashReporter::GetEnabled()) return NS_ERROR_NOT_INITIALIZED;
1763 nsAutoString path;
1764 if (!CrashReporter::GetMinidumpPath(path)) return NS_ERROR_FAILURE;
1766 nsresult rv = NS_NewLocalFile(path, false, aMinidumpPath);
1767 NS_ENSURE_SUCCESS(rv, rv);
1768 return NS_OK;
1771 NS_IMETHODIMP
1772 nsXULAppInfo::SetMinidumpPath(nsIFile* aMinidumpPath) {
1773 nsAutoString path;
1774 nsresult rv = aMinidumpPath->GetPath(path);
1775 NS_ENSURE_SUCCESS(rv, rv);
1776 return CrashReporter::SetMinidumpPath(path);
1779 NS_IMETHODIMP
1780 nsXULAppInfo::GetMinidumpForID(const nsAString& aId, nsIFile** aMinidump) {
1781 if (!CrashReporter::GetMinidumpForID(aId, aMinidump)) {
1782 return NS_ERROR_FILE_NOT_FOUND;
1785 return NS_OK;
1788 NS_IMETHODIMP
1789 nsXULAppInfo::GetExtraFileForID(const nsAString& aId, nsIFile** aExtraFile) {
1790 if (!CrashReporter::GetExtraFileForID(aId, aExtraFile)) {
1791 return NS_ERROR_FILE_NOT_FOUND;
1794 return NS_OK;
1797 NS_IMETHODIMP
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);
1803 return NS_OK;
1806 NS_IMETHODIMP
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);
1811 return NS_OK;
1814 NS_IMETHODIMP
1815 nsXULAppInfo::IsAnnotationAllowedForPing(const nsACString& aValue,
1816 bool* aIsAllowed) {
1817 auto annotation = CrashReporter::AnnotationFromString(aValue);
1818 NS_ENSURE_TRUE(annotation.isSome(), NS_ERROR_INVALID_ARG);
1819 *aIsAllowed = CrashReporter::IsAnnotationAllowedForPing(*annotation);
1821 return NS_OK;
1824 NS_IMETHODIMP
1825 nsXULAppInfo::AppendAppNotesToCrashReport(const nsACString& data) {
1826 return CrashReporter::AppendAppNotesToCrashReport(data);
1829 NS_IMETHODIMP
1830 nsXULAppInfo::RegisterAppMemory(uint64_t pointer, uint64_t len) {
1831 return CrashReporter::RegisterAppMemory((void*)pointer, len);
1834 NS_IMETHODIMP
1835 nsXULAppInfo::WriteMinidumpForException(void* aExceptionInfo) {
1836 #ifdef XP_WIN
1837 return CrashReporter::WriteMinidumpForException(
1838 static_cast<EXCEPTION_POINTERS*>(aExceptionInfo));
1839 #else
1840 return NS_ERROR_NOT_IMPLEMENTED;
1841 #endif
1844 NS_IMETHODIMP
1845 nsXULAppInfo::AppendObjCExceptionInfoToAppNotes(void* aException) {
1846 #ifdef XP_MACOSX
1847 return CrashReporter::AppendObjCExceptionInfoToAppNotes(aException);
1848 #else
1849 return NS_ERROR_NOT_IMPLEMENTED;
1850 #endif
1853 NS_IMETHODIMP
1854 nsXULAppInfo::GetSubmitReports(bool* aEnabled) {
1855 return CrashReporter::GetSubmitReports(aEnabled);
1858 NS_IMETHODIMP
1859 nsXULAppInfo::SetSubmitReports(bool aEnabled) {
1860 return CrashReporter::SetSubmitReports(aEnabled);
1863 NS_IMETHODIMP
1864 nsXULAppInfo::UpdateCrashEventsDir() {
1865 CrashReporter::UpdateCrashEventsDir();
1866 return NS_OK;
1869 NS_IMETHODIMP
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))) {
1877 return rv;
1880 nsString path;
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))) {
1892 return rv;
1894 return NS_OK;
1897 // This method is from nsIFInishDumpingCallback.
1898 NS_IMETHODIMP
1899 nsXULAppInfo::Callback(nsISupports* aData) {
1900 nsCOMPtr<nsIFile> file = do_QueryInterface(aData);
1901 MOZ_ASSERT(file);
1903 CrashReporter::SetMemoryReportFile(file);
1904 return NS_OK;
1907 static const nsXULAppInfo kAppInfo;
1908 namespace mozilla {
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) \
1917 PR_BEGIN_MACRO \
1918 if (MOZ_UNLIKELY(!(x))) { \
1919 NS_WARNING("NS_ENSURE_TRUE(" #x ") failed"); \
1920 gLogConsoleErrors = true; \
1921 return ret; \
1923 PR_END_MACRO
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 {
1935 public:
1936 ScopedXPCOMStartup() : mServiceManager(nullptr) {}
1937 ~ScopedXPCOMStartup();
1939 nsresult Initialize(bool aInitJSContext = true);
1940 nsresult SetWindowCreator(nsINativeAppSupport* native);
1942 private:
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) {
1953 #ifdef XP_MACOSX
1954 // On OS X, we need a pool to catch cocoa objects that are autoreleased
1955 // during teardown.
1956 mozilla::MacAutoreleasePool pool;
1957 #endif
1959 nsCOMPtr<nsIAppStartup> appStartup(components::AppStartup::Service());
1960 if (appStartup) appStartup->DestroyHiddenWindow();
1962 gDirServiceProvider->DoShutdown();
1963 PROFILER_MARKER_UNTYPED("Shutdown early", OTHER);
1965 WriteConsoleLog();
1967 NS_ShutdownXPCOM(mServiceManager);
1968 mServiceManager = nullptr;
1972 nsresult ScopedXPCOMStartup::Initialize(bool aInitJSContext) {
1973 NS_ASSERTION(gDirServiceProvider, "Should not get here!");
1975 nsresult rv;
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;
1982 } else {
1983 #ifdef DEBUG
1984 nsCOMPtr<nsIComponentRegistrar> reg = do_QueryInterface(mServiceManager);
1985 NS_ASSERTION(reg, "Service Manager doesn't QI to Registrar.");
1986 #endif
1989 return rv;
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 {
1997 public:
1998 NS_DECL_ISUPPORTS
1999 NS_DECL_NSIFACTORY
2001 explicit nsSingletonFactory(nsISupports* aSingleton);
2003 private:
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)
2015 NS_IMETHODIMP
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) {
2024 nsresult rv;
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) {
2040 return nullptr;
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();
2051 #endif
2053 nsINativeAppSupport* ScopedXPCOMStartup::gNativeAppSupport;
2055 static void DumpArbitraryHelp() {
2056 nsresult rv;
2058 ScopedLogging log;
2061 ScopedXPCOMStartup xpcom;
2062 xpcom.Initialize();
2064 nsCOMPtr<nsICommandLineRunner> cmdline(new nsCommandLine());
2066 nsCString text;
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() {
2076 printf(
2077 "Usage: %s [ options ... ] [URL]\n"
2078 " where options include:\n\n",
2079 gArgv[0]);
2081 #ifdef MOZ_X11
2082 printf(
2083 "X11 options\n"
2084 " --display=DISPLAY X display to use\n"
2085 " --sync Make X calls synchronous\n");
2086 #endif
2087 #ifdef XP_UNIX
2088 printf(
2089 " --g-fatal-warnings Make all warnings fatal\n"
2090 "\n%s options\n",
2091 (const char*)gAppData->name);
2092 #endif
2094 printf(
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 "
2106 "instance.\n"
2107 #endif
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"
2111 #endif
2112 " --MOZ_LOG=<modules> Treated as MOZ_LOG=<modules> environment "
2113 "variable,\n"
2114 " overrides it.\n"
2115 " --MOZ_LOG_FILE=<file> Treated as MOZ_LOG_FILE=<file> environment "
2116 "variable,\n"
2117 " overrides it. If MOZ_LOG_FILE is not specified as "
2118 "an\n"
2119 " argument or as an environment variable, logging "
2120 "will be\n"
2121 " written to stdout.\n",
2122 (const char*)gAppData->name, (const char*)gAppData->name);
2124 #if defined(XP_WIN)
2125 printf(" --console Start %s with a debugging console.\n",
2126 (const char*)gAppData->name);
2127 #endif
2129 #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) || defined(XP_MACOSX)
2130 printf(" --headless Run without a GUI.\n");
2131 #endif
2133 #if defined(MOZ_ENABLE_DBUS)
2134 printf(
2135 " --dbus-service <launcher> Run as DBus service for "
2136 "org.freedesktop.Application and\n"
2137 " set a launcher (usually /usr/bin/appname "
2138 "script) for it.");
2139 #endif
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);
2160 printf("\n");
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);
2178 printf("\n");
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);
2189 #ifdef XP_WIN
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;
2200 if (rc == S_OK) {
2201 wasRegistered = true;
2204 if (Preferences::GetBool(PREF_WIN_REGISTER_APPLICATION_RESTART, false) &&
2205 !wasRegistered) {
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) {
2256 Unused << aPref;
2257 Unused << aData;
2259 bool shouldBeEnabled =
2260 Preferences::GetBool(kPrefPreXulSkeletonUI, false) &&
2261 Preferences::GetBool(kPrefBrowserStartupBlankWindow, false) &&
2262 LookAndFeel::DrawInTitlebar();
2263 if (shouldBeEnabled && Preferences::HasUserValue(kPrefThemeId)) {
2264 nsCString themeId;
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);
2272 } else {
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
2319 return;
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) {
2360 nsresult rv;
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);
2377 return NS_OK;
2380 static void OnDefaultAgentTelemetryPrefChanged(const char* aPref, void* aData) {
2381 nsresult rv;
2382 nsAutoString valueName;
2383 if (strcmp(aPref, kPrefHealthReportUploadEnabled) == 0) {
2384 valueName.AssignLiteral("DisableTelemetry");
2385 } else if (strcmp(aPref, kPrefDefaultAgentEnabled) == 0) {
2386 valueName.AssignLiteral("DisableDefaultBrowserAgent");
2387 } else {
2388 return;
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,
2410 void* aData) {
2411 nsresult rv;
2412 if (strcmp(aPref, kPrefSetDefaultBrowserUserChoicePref) != 0) {
2413 return;
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,
2436 void* aData) {
2437 nsresult rv;
2438 nsAutoString valueName;
2439 if (strcmp(aPref, kPrefServicesSettingsServer) == 0) {
2440 valueName.AssignLiteral("ServicesSettingsServer");
2441 } else {
2442 return;
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)) {
2461 return;
2464 if (prefVal.IsEmpty()) {
2465 rv = regKey->RemoveValue(valueName);
2466 } else {
2467 rv = regKey->WriteStringValue(valueName, prefVal);
2469 NS_ENSURE_SUCCESS_VOID(rv);
2472 static void SetDefaultAgentLastRunTime() {
2473 nsresult rv;
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);
2489 FILETIME fileTime;
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)
2502 #endif // XP_WIN
2504 void UnlockProfile() {
2505 if (gProfileLock) {
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.
2514 #ifdef MOZ_JPROF
2515 // make sure JPROF doesn't think we're E10s
2516 unsetenv("JPROF_ISCHILD");
2517 #endif
2519 if (aBlankCommandLine) {
2520 gRestartArgc = 1;
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)
2531 InitializeMacApp();
2532 CommandLineServiceMac::SetupMacCommandLine(gRestartArgc, gRestartArgv, true);
2533 LaunchMacApp(gRestartArgc, gRestartArgv);
2534 # else
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;
2544 HANDLE hProcess;
2545 if (!WinLaunchChild(exePath.get(), gRestartArgc, gRestartArgv, nullptr,
2546 &hProcess))
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);
2554 # else
2555 nsAutoCString exePath;
2556 rv = lf->GetNativePath(exePath);
2557 if (NS_FAILED(rv)) return rv;
2559 # if defined(XP_UNIX)
2560 if (aTryExec) {
2561 execv(exePath.get(), gRestartArgv);
2563 // If execv returns we know it's because it failed.
2564 return NS_ERROR_FAILURE;
2566 # endif
2567 if (PR_CreateProcessDetached(exePath.get(), gRestartArgv, nullptr, nullptr) ==
2568 PR_FAILURE) {
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
2574 // exit status.
2576 # endif // WP_WIN
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";
2586 namespace {
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 {
2593 public:
2594 MOZ_IMPLICIT ReturnAbortOnError(nsresult aRv) { mRv = ConvertRv(aRv); }
2596 operator nsresult() { return mRv; }
2598 private:
2599 inline nsresult ConvertRv(nsresult aRv) {
2600 if (NS_SUCCEEDED(aRv) || aRv == NS_ERROR_LAUNCHED_CHILD_PROCESS) {
2601 return aRv;
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()) {
2608 return aRv;
2610 #endif
2611 return NS_ERROR_ABORT;
2614 nsresult mRv;
2617 } // namespace
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
2624 // default one.
2625 Output(true, "Could not find profile folder.\n");
2626 return NS_ERROR_ABORT;
2627 #else
2628 # ifdef MOZ_BACKGROUNDTASKS
2629 if (BackgroundTasks::IsBackgroundTaskMode()) {
2630 // We should never get to this point in background task mode.
2631 printf_stderr(
2632 "Could not determine any profile running in backgroundtask mode!\n");
2633 return NS_ERROR_ABORT;
2635 # endif // MOZ_BACKGROUNDTASKS
2637 nsresult rv;
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
2647 // shutdown
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};
2659 // profileMissing
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) {
2684 nsresult rv;
2686 bool exists;
2687 aProfileDir->Exists(&exists);
2688 if (!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);
2700 #endif
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
2706 // shutdown
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;
2719 #ifndef XP_MACOSX
2720 rv = sb->FormatStringFromName(
2721 aUnlocker ? "restartMessageUnlocker" : "restartMessageNoUnlocker2",
2722 params, killMessage);
2723 #else
2724 rv = sb->FormatStringFromName(
2725 aUnlocker ? "restartMessageUnlockerMac" : "restartMessageNoUnlockerMac",
2726 params, killMessage);
2727 #endif
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;
2741 #endif
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);
2752 if (aUnlocker) {
2753 int32_t button;
2754 #ifdef MOZ_WIDGET_ANDROID
2755 // On Android we always kill the process if the lock is still being held
2756 button = 0;
2757 #else
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);
2768 #endif
2770 if (button == 0) {
2771 rv = aUnlocker->Unlock(nsIProfileUnlocker::FORCE_QUIT);
2772 if (NS_FAILED(rv)) {
2773 return 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();
2783 #endif
2784 return LaunchChild(false, true);
2786 } else {
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) {
2798 nsresult rv;
2800 nsCOMPtr<nsIFile> profD, profLD;
2801 bool offline = false;
2802 int32_t dialogReturn;
2805 ScopedXPCOMStartup xpcom;
2806 rv = xpcom.Initialize();
2807 NS_ENSURE_SUCCESS(rv, rv);
2809 rv = xpcom.SetWindowCreator(aNative);
2810 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
2812 #ifdef XP_MACOSX
2813 InitializeMacApp();
2814 CommandLineServiceMac::SetupMacCommandLine(gRestartArgc, gRestartArgv,
2815 true);
2816 #endif
2818 { // extra scoping is needed so we release these components before xpcom
2819 // shutdown
2820 nsCOMPtr<nsIWindowWatcher> windowWatcher(
2821 do_GetService(NS_WINDOWWATCHER_CONTRACTID));
2822 nsCOMPtr<nsIDialogParamBlock> ioParamBlock(
2823 do_CreateInstance(NS_DIALOGPARAMBLOCK_CONTRACTID));
2824 nsCOMPtr<nsIMutableArray> dlgArray(
2825 do_CreateInstance(NS_ARRAY_CONTRACTID));
2826 NS_ENSURE_TRUE(windowWatcher && ioParamBlock && dlgArray,
2827 NS_ERROR_FAILURE);
2829 ioParamBlock->SetObjects(dlgArray);
2831 nsCOMPtr<nsIAppStartup> appStartup(components::AppStartup::Service());
2832 NS_ENSURE_TRUE(appStartup, NS_ERROR_FAILURE);
2834 nsAutoCString features("centerscreen,chrome,modal,titlebar");
2835 // If we're launching a private browsing window make sure to set that
2836 // feature for the Profile Manager window as well, so it groups correctly
2837 // on the Windows taskbar.
2838 if (CheckArgExists("private-window") == ARG_FOUND) {
2839 features.AppendLiteral(",private");
2841 nsCOMPtr<mozIDOMWindowProxy> newWindow;
2842 rv = windowWatcher->OpenWindow(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);
2867 if (offline) {
2868 SaveToEnv("XRE_START_OFFLINE=1");
2871 // User requested that we restart back into the profile manager.
2872 if (dialogReturn == nsIToolkitProfileService::restart) {
2873 SaveToEnv("XRE_RESTART_TO_PROFILE_MANAGER=1");
2874 } else {
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.
2883 char** newArgv =
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();
2894 #endif
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,
2905 kTelemetryEnv);
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,
2914 kTelemetryEnv);
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;
2932 nsresult rv;
2933 nsCOMPtr<nsIProfileUnlocker> unlocker;
2934 const TimeStamp start = TimeStamp::Now();
2935 do {
2936 if (aProfile) {
2937 rv = aProfile->Lock(getter_AddRefs(unlocker), aResult);
2938 } else {
2939 rv = NS_LockProfilePath(aRootDir, aLocalDir, getter_AddRefs(unlocker),
2940 aResult);
2942 if (NS_SUCCEEDED(rv)) {
2943 StartupTimeline::Record(StartupTimeline::AFTER_PROFILE_LOCKED);
2944 return NS_OK;
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);
2968 nsresult rv;
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
2976 // chosen below.
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;
2987 #if defined(XP_WIN)
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");
2995 #endif
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);
3013 if (didCreate) {
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...
3028 if (!*aRootDir) {
3029 NS_WARNING("Failed to select or create profile.");
3030 return NS_ERROR_ABORT;
3033 return NS_OK;
3036 #ifdef MOZ_BLOCK_PROFILE_DOWNGRADE
3037 struct FileWriteFunc final : public JSONWriteFunc {
3038 FILE* mFile;
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);
3055 bool enabled;
3056 nsresult rv =
3057 prefBranch->GetBoolPref(kPrefHealthReportUploadEnabled, &enabled);
3058 NS_ENSURE_SUCCESS_VOID(rv);
3059 if (!enabled) {
3060 return;
3063 nsCString server;
3064 rv = prefBranch->GetCharPref("toolkit.telemetry.server", server);
3065 NS_ENSURE_SUCCESS_VOID(rv);
3067 nsCString clientId;
3068 rv = prefBranch->GetCharPref("toolkit.telemetry.cachedClientID", clientId);
3069 NS_ENSURE_SUCCESS_VOID(rv);
3071 nsCString profileGroupId;
3072 rv = prefBranch->GetCharPref("toolkit.telemetry.cachedProfileGroupID",
3073 profileGroupId);
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);
3083 nsID uuid;
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);
3093 time_t now;
3094 time(&now);
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) {
3103 return;
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) {
3124 return;
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);
3132 # ifdef XP_WIN
3133 pingSender->Append(u"pingsender.exe"_ns);
3134 # else
3135 pingSender->Append(u"pingsender"_ns);
3136 # endif
3138 bool exists;
3139 rv = pingSender->Exists(&exists);
3140 NS_ENSURE_SUCCESS_VOID(rv);
3141 if (!exists) {
3142 return;
3145 FILE* file;
3146 rv = pingFile->OpenANSIFileDesc("w", &file);
3147 NS_ENSURE_SUCCESS_VOID(rv);
3149 JSONWriter w(MakeUnique<FileWriteFunc>(file));
3150 w.Start();
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);
3162 w.StringProperty(
3163 "buildId",
3164 MakeStringSpan(static_cast<const char*>(gAppData->buildID)));
3165 w.StringProperty(
3166 "name", MakeStringSpan(static_cast<const char*>(gAppData->name)));
3167 w.StringProperty(
3168 "version",
3169 MakeStringSpan(static_cast<const char*>(gAppData->version)));
3170 w.StringProperty("displayVersion",
3171 MOZ_STRINGIFY(MOZ_APP_VERSION_DISPLAY));
3172 w.StringProperty(
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);
3177 # else
3178 w.StringProperty("xpcomAbi", "unknown");
3179 # endif
3180 w.StringProperty("channel", channel);
3182 w.EndObject();
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);
3190 w.EndObject();
3192 w.End();
3194 fclose(file);
3196 PathString filePath = pingFile->NativePath();
3197 const filesystem::Path::value_type* args[2];
3198 # ifdef XP_WIN
3199 nsString urlw = NS_ConvertUTF8toUTF16(url);
3200 args[0] = urlw.get();
3201 # else
3202 args[0] = url.get();
3203 # endif
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);
3213 # ifdef XP_WIN
3214 process->Runw(false, args, 2);
3215 # else
3216 process->Run(false, args, 2);
3217 # endif
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) {
3227 int32_t result = 0;
3228 nsresult rv;
3231 if (gfxPlatform::IsHeadless()) {
3232 // TODO: make a way to turn off all dialogs when headless.
3233 Output(true,
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
3247 // shutdown
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);
3279 uint8_t flags = 0;
3280 if (hasSync) {
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));
3311 # endif
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);
3333 // Cancel
3334 return NS_ERROR_ABORT;
3336 #endif
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) {
3354 NS_WARNING(
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);
3360 return;
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")) {
3379 return -1;
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
3402 * updated.
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) {
3412 *aCachesOK = false;
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);
3422 nsINIParser parser;
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)) {
3428 return false;
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);
3436 return false;
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);
3445 nsAutoCString buf;
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;
3459 bool eq;
3460 rv = lf->Equals(aXULRunnerDir, &eq);
3461 if (NS_FAILED(rv) || !eq) return false;
3463 if (aAppDir) {
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)) &&
3483 purgeCaches) {
3484 *aCachesOK = false;
3487 return true;
3490 void BuildCompatVersion(const char* aAppVersion, const char* aAppBuildID,
3491 const char* aToolkitBuildID, nsACString& aBuf) {
3492 aBuf.Assign(aAppVersion);
3493 aBuf.Append('_');
3494 aBuf.Append(aAppBuildID);
3495 aBuf.Append('/');
3496 aBuf.Append(aToolkitBuildID);
3499 static void BuildVersion(nsCString& aBuf) {
3500 BuildCompatVersion(gAppData->version, gAppData->buildID, gToolkitBuildID,
3501 aBuf);
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));
3509 if (!file) return;
3510 file->AppendNative(FILE_COMPATIBILITY_INFO);
3512 nsAutoCString platformDir;
3513 Unused << aXULRunnerDir->GetPersistentDescriptor(platformDir);
3515 nsAutoCString appDir;
3516 if (aAppDir) Unused << aAppDir->GetPersistentDescriptor(appDir);
3518 PRFileDesc* fd;
3519 nsresult rv = file->OpenNSPRFileDesc(PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE,
3520 0600, &fd);
3521 if (NS_FAILED(rv)) {
3522 NS_ERROR("could not create output stream");
3523 return;
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=";
3541 if (aAppDir) {
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);
3553 PR_Close(fd);
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
3585 // if needed.
3586 static void MakeOrSetMinidumpPath(nsIFile* profD) {
3587 nsCOMPtr<nsIFile> dumpD;
3588 profD->Clone(getter_AddRefs(dumpD));
3590 if (dumpD) {
3591 bool fileExists;
3592 // XXX: do some more error checking here
3593 dumpD->Append(u"minidumps"_ns);
3594 dumpD->Exists(&fileExists);
3595 if (!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) {
3633 HKEY dummyKey;
3634 HRESULT hr;
3635 wchar_t buf[512];
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);
3643 # else
3645 # define LOGREGISTRY(msg)
3647 # endif
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");
3653 if (dwdll) {
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");
3665 factory->Release();
3666 LOGREGISTRY(L"freed factory");
3667 } else {
3668 LOGREGISTRY(L"failed to create factory");
3672 SetThreadPriority(GetCurrentThread(), THREAD_MODE_BACKGROUND_END);
3673 return 0;
3675 #endif
3677 #include "GeckoProfiler.h"
3678 #include "ProfilerControl.h"
3680 // Encapsulates startup and shutdown state for XRE_main
3681 class XREMain {
3682 public:
3683 XREMain() = default;
3685 ~XREMain() {
3686 mScopedXPCOM = nullptr;
3687 mAppData = 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;
3711 #endif
3713 bool mStartOffline = false;
3714 nsAutoCString mOriginToForceQUIC;
3715 #if defined(MOZ_HAS_REMOTE)
3716 bool mDisableRemoteClient = false;
3717 #endif
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[] = {
3731 "HOME",
3732 # ifdef MOZ_WIDGET_GTK
3733 "XDG_RUNTIME_DIR",
3734 # endif
3735 # ifdef MOZ_X11
3736 "XAUTHORITY",
3737 # endif
3740 const uid_t euid = geteuid();
3741 if (euid != 0) {
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
3746 // concerned about.
3747 return false;
3750 for (const auto var : kVars) {
3751 if (const auto path = PR_GetEnv(var)) {
3752 struct stat st;
3753 if (stat(path, &st) == 0) {
3754 if (st.st_uid != euid) {
3755 const auto owner = FormatUid(st.st_uid);
3756 Output(true,
3757 "Running " MOZ_APP_DISPLAYNAME
3758 " as root in a regular"
3759 " user's session is not supported. ($%s is %s which is"
3760 " owned by %s.)\n",
3761 var, path, owner.get());
3762 return true;
3767 return false;
3769 #else // !XP_UNIX || ANDROID
3770 static bool CheckForUserMismatch() { return false; }
3771 #endif
3773 void mozilla::startup::IncreaseDescriptorLimits() {
3774 #ifdef XP_UNIX
3775 // Increase the fd limit to accomodate IPC resources like shared memory.
3776 # ifdef XP_DARWIN
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
3785 struct rlimit rlim;
3787 if (getrlimit(RLIMIT_NOFILE, &rlim) != 0) {
3788 Output(false, "getrlimit: %s\n", strerror(errno));
3789 return;
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;
3798 } else {
3799 rlim.rlim_cur = kFDs;
3801 if (setrlimit(RLIMIT_NOFILE, &rlim) != 0) {
3802 Output(false, "setrlimit: %s\n", strerror(errno));
3805 #endif
3808 #ifdef XP_WIN
3810 static uint32_t GetMicrocodeVersionByVendor(HKEY key, DWORD upper,
3811 DWORD lower) {
3812 WCHAR data[13]; // The CPUID vendor string is 12 characters long plus null
3813 DWORD len = sizeof(data);
3814 DWORD vtype;
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
3820 return upper;
3823 if (wcscmp(L"AuthenticAMD", data) == 0) {
3824 // AMD reports the microcode version in the lower 32 bits of the MSR
3825 return lower;
3828 // Unknown CPU vendor, return whatever half is non-zero
3829 return lower ? lower : upper;
3832 return 0; // No clue
3835 #endif // XP_WIN
3837 static void MaybeAddCPUMicrocodeCrashAnnotation() {
3838 #ifdef XP_WIN
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;
3842 HKEY key;
3843 static const WCHAR keyName[] =
3844 L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0";
3846 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, keyName, 0, KEY_QUERY_VALUE, &key) ==
3847 ERROR_SUCCESS) {
3848 DWORD updateRevision[2];
3849 DWORD len = sizeof(updateRevision);
3850 DWORD vtype;
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]);
3864 break;
3867 if (vtype == REG_DWORD && len == sizeof(updateRevision[0])) {
3868 cpuUpdateRevision = static_cast<int>(updateRevision[0]);
3869 break;
3875 if (cpuUpdateRevision > 0) {
3876 CrashReporter::RecordAnnotationNSCString(
3877 CrashReporter::Annotation::CPUMicrocodeVersion,
3878 nsPrintfCString("0x%" PRIx32, cpuUpdateRevision));
3880 #endif
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
3888 // the console.
3889 // 2. Suppressing output intermittently causes failures on when running
3890 // multiple tasks (see bug 1831631)
3891 # ifndef XP_WIN
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);
3899 return;
3901 # endif
3902 printf_stderr("*** You are running in background task mode. ***\n");
3904 #endif
3907 * XRE_mainInit - Initial setup and command line parameter processing.
3908 * Main() will exit early if either return value != 0 or if aExitFlag is
3909 * true.
3911 int XREMain::XRE_mainInit(bool* aExitFlag) {
3912 if (!aExitFlag) return 1;
3913 *aExitFlag = false;
3915 atexit(UnexpectedExit);
3916 auto expectedShutdown = mozilla::MakeScopeExit([&] { MozExpectedExit(); });
3918 StartupTimeline::Record(StartupTimeline::MAIN);
3920 if (CheckForUserMismatch()) {
3921 return 1;
3924 #ifdef XP_MACOSX
3925 mozilla::MacAutoreleasePool pool;
3927 DisableAppNap();
3928 #endif
3930 #ifdef MOZ_BACKGROUNDTASKS
3931 Maybe<nsCString> backgroundTask = Nothing();
3932 const char* backgroundTaskName = nullptr;
3933 if (ARG_FOUND ==
3934 CheckArg("backgroundtask", &backgroundTaskName, CheckArgFlag::None)) {
3935 backgroundTask = Some(backgroundTaskName);
3937 SetupConsoleForBackgroundTask(backgroundTask.ref());
3940 BackgroundTasks::Init(backgroundTask);
3941 #endif
3943 #ifndef ANDROID
3944 if (PR_GetEnv("MOZ_RUN_GTEST")
3945 # ifdef FUZZING
3946 || PR_GetEnv("FUZZER")
3947 # endif
3948 # ifdef MOZ_BACKGROUNDTASKS
3949 || BackgroundTasks::IsBackgroundTaskMode()
3950 # endif
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());
3959 #endif // ANDROID
3961 if (PR_GetEnv("MOZ_CHAOSMODE")) {
3962 ChaosFeature feature = ChaosFeature::Any;
3963 long featureInt = strtol(PR_GetEnv("MOZ_CHAOSMODE"), nullptr, 16);
3964 if (featureInt) {
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)) {
3976 printf_stderr(
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");
3987 #else
3988 Output(
3989 true,
3990 "Error: headless mode is not currently supported on this platform.\n");
3991 return 1;
3992 #endif
3994 #ifdef XP_MACOSX
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.");
4002 return 1;
4004 #endif
4007 gKioskMode = CheckArg("kiosk", nullptr, CheckArgFlag::None);
4008 const char* kioskMonitorNumber = nullptr;
4009 if (CheckArg("kiosk-monitor", &kioskMonitorNumber, CheckArgFlag::None)) {
4010 gKioskMode = true;
4011 gKioskMonitor = atoi(kioskMonitorNumber);
4014 if (XRE_IsParentProcess()) {
4015 gAllowContentAnalysisArgPresent =
4016 CheckArg("allow-content-analysis", nullptr, CheckArgFlag::None) ==
4017 ARG_FOUND;
4020 nsresult rv;
4021 ArgResult ar;
4023 #ifdef DEBUG
4024 if (PR_GetEnv("XRE_MAIN_BREAK")) NS_BREAK();
4025 #endif
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);
4045 #endif
4047 #ifdef XP_UNIX
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");
4053 return 1;
4055 SaveWordToEnv("HOME", nsDependentCString(pw->pw_dir));
4057 #endif
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");
4063 #endif
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");
4070 return 1;
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");
4077 return 1;
4080 rv = XRE_ParseAppData(overrideLF, *mAppData);
4081 if (NS_FAILED(rv)) {
4082 Output(true, "Couldn't read override.ini");
4083 return 1;
4087 // Check sanity and correctness of app data.
4089 if (!mAppData->name) {
4090 Output(true, "Error: App:Name not specified in application.ini\n");
4091 return 1;
4093 if (!mAppData->buildID) {
4094 Output(true, "Error: App:BuildID not specified in application.ini\n");
4095 return 1;
4098 // XXX Originally ScopedLogging was here? Now it's in XRE_main above
4099 // XRE_mainInit.
4101 if (!mAppData->minVersion) {
4102 Output(true, "Error: Gecko:MinVersion not specified in application.ini\n");
4103 return 1;
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) {
4114 Output(true,
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);
4119 return 1;
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,
4146 true);
4148 // pass some basic info from the app data
4149 if (mAppData->vendor) {
4150 CrashReporter::RecordAnnotationCString(CrashReporter::Annotation::Vendor,
4151 mAppData->vendor);
4153 if (mAppData->name) {
4154 CrashReporter::RecordAnnotationCString(
4155 CrashReporter::Annotation::ProductName, mAppData->name);
4157 if (mAppData->ID) {
4158 CrashReporter::RecordAnnotationCString(
4159 CrashReporter::Annotation::ProductID, mAppData->ID);
4161 if (mAppData->version) {
4162 CrashReporter::RecordAnnotationCString(CrashReporter::Annotation::Version,
4163 mAppData->version);
4165 if (mAppData->buildID) {
4166 CrashReporter::RecordAnnotationCString(CrashReporter::Annotation::BuildID,
4167 mAppData->buildID);
4170 nsDependentCString releaseChannel(MOZ_STRINGIFY(MOZ_UPDATE_CHANNEL));
4171 CrashReporter::RecordAnnotationNSCString(
4172 CrashReporter::Annotation::ReleaseChannel, releaseChannel);
4174 #ifdef XP_WIN
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));
4188 #endif
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());
4198 #endif
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
4215 // directory
4216 nsCOMPtr<nsIFile> overrideini;
4217 if (NS_SUCCEEDED(
4218 mDirProvider.GetAppDir()->Clone(getter_AddRefs(overrideini))) &&
4219 NS_SUCCEEDED(
4220 overrideini->AppendNative("crashreporter-override.ini"_ns))) {
4221 #ifdef XP_WIN
4222 nsAutoString overridePathW;
4223 overrideini->GetPath(overridePathW);
4224 NS_ConvertUTF16toUTF8 overridePath(overridePathW);
4225 #else
4226 nsAutoCString overridePath;
4227 overrideini->GetNativePath(overridePath);
4228 #endif
4230 SaveWordToEnv("MOZ_CRASHREPORTER_STRINGS_OVERRIDE", overridePath);
4233 } else {
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);
4245 } else {
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.");
4252 # endif
4253 // Otherwise just warn for the moment, as most things will work.
4254 NS_WARNING(
4255 "Failed to initialize broker services, sandboxed processes will "
4256 "fail to start.");
4258 #endif
4260 #ifdef XP_MACOSX
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}};
4279 EventRef event;
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);
4291 #endif
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;
4302 gRestartArgv =
4303 (char**)malloc(sizeof(char*) * (gArgc + 1 + (override ? 2 : 0)));
4304 if (!gRestartArgv) {
4305 return 1;
4308 int i;
4309 for (i = 0; i < gArgc; ++i) {
4310 gRestartArgv[i] = gArgv[i];
4313 // Add the -override argument back (it is removed automatically be CheckArg)
4314 // if there is one
4315 if (override) {
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) {
4324 return 1;
4326 #ifdef MOZ_BACKGROUNDTASKS
4327 if (BackgroundTasks::IsBackgroundTaskMode()) {
4328 safeModeRequested = Some(false);
4330 // Remove the --backgroundtask arg now that it has been saved in
4331 // gRestartArgv.
4332 const char* tmpBackgroundTaskName = nullptr;
4333 Unused << CheckArg("backgroundtask", &tmpBackgroundTaskName,
4334 CheckArgFlag::RemoveArg);
4336 #endif
4338 gSafeMode = safeModeRequested.value();
4340 MaybeAddCPUMicrocodeCrashAnnotation();
4341 CrashReporter::RegisterAnnotationBool(CrashReporter::Annotation::SafeMode,
4342 &gSafeMode);
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;
4354 #else
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");
4358 #endif
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("?")) {
4380 DumpHelp();
4381 *aExitFlag = true;
4382 return 0;
4385 if (CheckArg("v") || CheckArg("version")) {
4386 DumpVersion();
4387 *aExitFlag = true;
4388 return 0;
4391 if (CheckArg("full-version")) {
4392 DumpFullVersion();
4393 *aExitFlag = true;
4394 return 0;
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");
4402 return 1;
4404 if (ar == ARG_FOUND) {
4405 UniquePtr<DBusService> dbusService =
4406 MakeUnique<DBusService>(dbusServiceLauncher);
4407 if (dbusService->Init()) {
4408 dbusService->Run();
4410 *aExitFlag = true;
4411 return 0;
4413 #endif
4415 rv = XRE_InitCommandLine(gArgc, gArgv);
4416 NS_ENSURE_SUCCESS(rv, 1);
4418 return 0;
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)
4432 #ifdef XP_WIN
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.
4456 if (greDir) {
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");
4467 } else {
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");
4483 #endif
4485 #if defined(MOZ_UPDATER) && !defined(MOZ_WIDGET_ANDROID)
4486 enum struct ShouldNotProcessUpdatesReason {
4487 DevToolsLaunching,
4488 NotAnUpdatingTask,
4489 OtherInstanceRunning,
4490 FirstStartup
4493 const char* ShouldNotProcessUpdatesReasonAsString(
4494 ShouldNotProcessUpdatesReason aReason) {
4495 switch (aReason) {
4496 case ShouldNotProcessUpdatesReason::DevToolsLaunching:
4497 return "DevToolsLaunching";
4498 case ShouldNotProcessUpdatesReason::NotAnUpdatingTask:
4499 return "NotAnUpdatingTask";
4500 case ShouldNotProcessUpdatesReason::OtherInstanceRunning:
4501 return "OtherInstanceRunning";
4502 default:
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;
4563 bool persistent;
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.
4568 return Nothing();
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);
4580 # endif
4582 return Nothing();
4584 #endif
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()) {
4602 return true;
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.
4609 AutoFDClose fd;
4610 Unused << crashFile.inspect()->OpenNSPRFileDesc(
4611 PR_WRONLY | PR_CREATE_FILE | PR_EXCL, 0666, getter_Transfers(fd));
4612 return !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
4618 * true.
4620 int XREMain::XRE_mainStartup(bool* aExitFlag) {
4621 nsresult rv;
4623 if (!aExitFlag) return 1;
4624 *aExitFlag = false;
4626 #ifdef XP_MACOSX
4627 mozilla::MacAutoreleasePool pool;
4628 #endif
4630 // Enable Telemetry IO Reporting on DEBUG, nightly and local builds,
4631 // but disable it on FUZZING builds and for ANDROID.
4632 #ifndef FUZZING
4633 # ifndef ANDROID
4634 # ifdef DEBUG
4635 mozilla::Telemetry::InitIOReporting(gAppData->xreDirectory);
4636 # else
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);
4644 # endif /* DEBUG */
4645 # endif /* ANDROID */
4646 #endif /* FUZZING */
4648 #if defined(XP_WIN)
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);
4653 #endif /* XP_WIN */
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);
4664 #endif
4666 #if defined(XP_WIN)
4668 // Save the shortcut path before lpTitle is replaced by an AUMID,
4669 // such as by WinTaskbar
4670 STARTUPINFOW si;
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);
4678 #endif /* XP_WIN */
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
4684 // consistently.
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();
4698 # endif
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
4702 // opens.
4703 if (!gtk_parse_args(&gArgc, &gArgv)) return 1;
4704 #endif /* MOZ_WIDGET_GTK */
4706 #ifdef FUZZING
4707 if (PR_GetEnv("FUZZER")) {
4708 *aExitFlag = true;
4709 return mozilla::fuzzerRunner->Run(&gArgc, &gArgv);
4711 #endif
4713 if (PR_GetEnv("MOZ_RUN_GTEST")) {
4714 int result;
4715 #ifdef XP_WIN
4716 UseParentConsole();
4717 #endif
4718 // RunGTest will only be set if we're in xul-unit
4719 if (mozilla::RunGTest) {
4720 gIsGtest = true;
4721 result = mozilla::RunGTest(&gArgc, gArgv);
4722 gIsGtest = false;
4723 } else {
4724 result = 1;
4725 printf("TEST-UNEXPECTED-FAIL | gtest | Not compiled with enable-tests\n");
4727 *aExitFlag = true;
4728 return result;
4731 bool isBackgroundTaskMode = false;
4732 #ifdef MOZ_BACKGROUNDTASKS
4733 isBackgroundTaskMode = BackgroundTasks::IsBackgroundTaskMode();
4734 #endif
4736 #ifdef MOZ_HAS_REMOTE
4737 if (gfxPlatform::IsHeadless()) {
4738 mDisableRemoteClient = true;
4740 #endif
4742 #ifdef MOZ_X11
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()) {
4747 XInitThreads();
4749 #endif
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();
4758 # ifdef MOZ_WAYLAND
4759 if (!display_name) {
4760 auto* proxyEnv = getenv("MOZ_DISABLE_WAYLAND_PROXY");
4761 bool disableWaylandProxy = proxyEnv && *proxyEnv;
4762 if (!disableWaylandProxy && XRE_IsParentProcess() && waylandEnabled) {
4763 # ifdef MOZ_LOGGING
4764 if (MOZ_LOG_TEST(gWidgetWaylandLog, mozilla::LogLevel::Debug)) {
4765 WaylandProxy::SetVerbose(true);
4767 # endif
4768 gWaylandProxy = WaylandProxy::Create();
4769 if (gWaylandProxy) {
4770 gWaylandProxy->RunThread();
4774 # endif
4776 // if --display argument is given make sure it's
4777 // also passed to ContentChild::Init() by MOZ_GDK_DISPLAY.
4778 if (display_name) {
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");
4790 return 1;
4794 if (display_name) {
4795 GdkDisplay* disp = gdk_display_open(display_name);
4796 if (!disp) {
4797 PR_fprintf(PR_STDERR, "Error: cannot open display: %s\n", display_name);
4798 return 1;
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));
4807 } else {
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
4821 // run with X11.
4822 Output(true,
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;
4832 # endif
4833 if (!gdk_display_get_default()) {
4834 Output(true,
4835 "Error: we don't have any display, WAYLAND_DISPLAY='%s' "
4836 "DISPLAY='%s'\n",
4837 PR_GetEnv("WAYLAND_DISPLAY"), PR_GetEnv("DISPLAY"));
4838 return 1;
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");
4845 return 1;
4847 # endif
4848 # if !defined(MOZ_WAYLAND) && defined(MOZ_X11)
4849 if (!GdkIsX11Display()) {
4850 Output(true, "X11 only build is missig X11 display!\n");
4851 return 1;
4853 # endif
4855 #endif
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();
4862 #endif
4863 #if defined(MOZ_WIDGET_GTK)
4864 g_set_application_name(mAppData->name);
4866 #endif /* defined(MOZ_WIDGET_GTK) */
4867 #ifdef MOZ_X11
4868 // Do this after initializing GDK, or GDK will install its own handler.
4869 XRE_InstallX11ErrorHandler();
4870 #endif
4872 // Call the code to install our handler
4873 #ifdef MOZ_JPROF
4874 setupProfilingStuff();
4875 #endif
4877 bool canRun = false;
4878 rv = mNativeApp->Start(&canRun);
4879 if (NS_FAILED(rv) || !canRun) {
4880 return 1;
4883 #ifdef MOZ_WIDGET_GTK
4884 // startup token might be cleared now, we recover it in case we need a
4885 // restart.
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));
4895 #endif
4897 // Support exiting early for testing startup sequence. Bug 1360493
4898 if (CheckArg("test-launch-without-hang")) {
4899 *aExitFlag = true;
4900 return 0;
4903 mProfileSvc = NS_GetToolkitProfileService();
4904 if (!mProfileSvc) {
4905 // We failed to choose or create profile - notify user and quit
4906 ProfileMissingDialog(mNativeApp);
4907 return 1;
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) {
4916 *aExitFlag = true;
4917 return 0;
4920 if (NS_FAILED(rv)) {
4921 // We failed to choose or create profile - notify user and quit
4922 ProfileMissingDialog(mNativeApp);
4923 return 1;
4926 #if defined(MOZ_HAS_REMOTE)
4927 if (gRemoteService) {
4928 // Use the full profile path to identify the profile.
4929 nsCString profilePath;
4931 # ifdef XP_WIN
4932 nsString path;
4933 rv = mProfD->GetPath(path);
4934 if (NS_SUCCEEDED(rv)) {
4935 CopyUTF16toUTF8(path, profilePath);
4937 # else
4938 rv = mProfD->GetNativePath(profilePath);
4939 # endif
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
4946 // normally.
4947 # ifdef MOZ_WIDGET_GTK
4948 auto& startupToken =
4949 GdkIsWaylandDisplay() ? mXDGActivationToken : mDesktopStartupID;
4950 # ifdef MOZ_X11
4951 if (GdkIsX11Display() && startupToken.IsEmpty()) {
4952 startupToken = SynthesizeStartupToken();
4954 # endif /* MOZ_X11 */
4955 gRemoteService->SetStartupToken(startupToken);
4956 # endif
4957 rv = gRemoteService->StartClient();
4959 if (rv == NS_ERROR_NOT_AVAILABLE && profile) {
4960 // Older versions would use the profile name in preference to the
4961 // path.
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)) {
4973 *aExitFlag = true;
4974 gRemoteService->UnlockStartup();
4975 return 0;
4978 if (rv == NS_ERROR_INVALID_ARG) {
4979 gRemoteService->UnlockStartup();
4980 return 1;
4985 #endif
4987 #if defined(MOZ_UPDATER) && !defined(MOZ_WIDGET_ANDROID)
4988 # ifdef XP_WIN
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) {
5004 printf_stderr(
5005 "*** MaybeWaitForProcessExit: launched pidDWORD = %u ***\n", pid);
5006 RefPtr<nsUpdateProcessor> updater = new nsUpdateProcessor();
5007 if (NS_FAILED(
5008 updater->WaitForProcessExit(pid, MAYBE_WAIT_TIMEOUT_MS))) {
5009 NS_WARNING("Failed to MaybeWaitForProcessExit.");
5011 } else {
5012 NS_WARNING("Failed to parse pid from -restart-pid.");
5016 # endif
5017 Maybe<ShouldNotProcessUpdatesReason> shouldNotProcessUpdatesReason =
5018 ShouldNotProcessUpdates(mDirProvider);
5019 if (shouldNotProcessUpdatesReason.isNothing()) {
5020 // Check for and process any available updates
5021 nsCOMPtr<nsIFile> updRoot;
5022 bool persistent;
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");
5039 if (logFP) {
5040 for (int i = 1; i < gRestartArgc; ++i) {
5041 fprintf(logFP, "%s\n", gRestartArgv[i]);
5043 fclose(logFP);
5046 *aExitFlag = true;
5047 return 0;
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=");
5068 *aExitFlag = true;
5069 return 0;
5071 } else {
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()))
5082 .get());
5085 #endif
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);
5099 if (showSelector) {
5100 rv = ShowProfileSelector(mProfileSvc, mNativeApp);
5101 } else {
5102 rv = NS_OK;
5106 if (rv == NS_ERROR_LAUNCHED_CHILD_PROCESS || rv == NS_ERROR_ABORT) {
5107 *aExitFlag = true;
5108 return 0;
5110 if (NS_FAILED(rv)) {
5111 return 1;
5114 // We always want to lock the profile even if we're actually going to reset
5115 // it later.
5116 rv = LockProfile(mNativeApp, mProfD, mProfLD, profile,
5117 getter_AddRefs(mProfileLock));
5118 if (rv == NS_ERROR_LAUNCHED_CHILD_PROCESS || rv == NS_ERROR_ABORT) {
5119 *aExitFlag = true;
5120 return 0;
5121 } else if (NS_FAILED(rv)) {
5122 return 1;
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) {
5155 *aExitFlag = true;
5156 return 0;
5157 } else if (NS_FAILED(rv)) {
5158 return 1;
5160 } else {
5161 NS_WARNING("Profile reset failed.");
5162 return 1;
5166 gProfileLock = mProfileLock;
5168 nsAutoCString version;
5169 BuildVersion(version);
5171 #ifdef TARGET_OS_ABI
5172 constexpr auto osABI = nsLiteralCString{TARGET_OS_ABI};
5173 #else
5174 // No TARGET_XPCOM_ABI, but at least the OS is known
5175 constexpr auto osABI = nsLiteralCString{OS_TARGET "_UNKNOWN"};
5176 #endif
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));
5190 if (flagFile) {
5191 flagFile->AppendNative(FILE_INVALIDATE_CACHES);
5194 bool cachesOK;
5195 bool isDowngrade;
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")) {
5209 # ifdef XP_MACOSX
5210 InitializeMacApp();
5211 # endif
5212 rv = CheckDowngrade(mProfD, mNativeApp, mProfileSvc, lastVersion);
5213 if (rv == NS_ERROR_LAUNCHED_CHILD_PROCESS || rv == NS_ERROR_ABORT) {
5214 *aExitFlag = true;
5215 return 0;
5218 #endif
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);
5243 #endif
5245 bool lastStartupWasCrash = CheckLastStartupWasCrash();
5247 CrashReporter::RecordAnnotationBool(
5248 CrashReporter::Annotation::LastStartupWasCrash, lastStartupWasCrash);
5250 if (CheckArg("purgecaches") || PR_GetEnv("MOZ_PURGE_CACHES") ||
5251 lastStartupWasCrash || gSafeMode) {
5252 cachesOK = false;
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();
5281 if (flagFile) {
5282 flagFile->Remove(true);
5285 // Flush any pending page load events.
5286 mozilla::glean_pings::Pageload.Submit("startup"_ns);
5288 if (!isBackgroundTaskMode) {
5289 #ifdef USE_GLX_TEST
5290 GfxInfo::FireGLXTestProcess();
5291 #endif
5292 #ifdef MOZ_WAYLAND
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());
5299 #endif
5300 #ifdef MOZ_WIDGET_GTK
5301 nsAppShell::InstallTermSignalHandler();
5302 #endif
5305 return 0;
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);
5330 # endif
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.");
5345 #if defined(XP_WIN)
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
5355 // it here.
5356 nsCOMPtr<nsIAppStartup> appStartup;
5357 // Ditto with the command line.
5358 nsCOMPtr<nsICommandLineRunner> cmdLine;
5361 #ifdef XP_MACOSX
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;
5365 #endif
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)) {
5378 nsAutoCString sval;
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);
5394 #endif
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));
5408 #ifdef XP_WIN
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();
5416 nsAutoString path;
5417 rv = greDir->GetPath(path);
5418 if (NS_SUCCEEDED(rv)) {
5419 PRThread* readAheadThread;
5420 wchar_t* pathRaw;
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());
5429 } else {
5430 pathRaw = nullptr;
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) {
5436 delete[] pathRaw;
5440 #endif
5442 if (gDoMigration) {
5443 nsCOMPtr<nsIFile> file;
5444 mDirProvider.GetAppDir()->Clone(getter_AddRefs(file));
5445 file->AppendNative("override.ini"_ns);
5446 nsINIParser parser;
5447 nsresult rv = parser.Init(file);
5448 // if override.ini doesn't exist, also check for distribution.ini
5449 if (NS_FAILED(rv)) {
5450 bool persistent;
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)) {
5457 nsAutoCString buf;
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
5471 // bug 1592523.
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));
5484 if (pm) {
5485 nsAutoCString aKey;
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);
5493 #ifdef XP_MACOSX
5494 // Necessary for migration wizard to be accessible.
5495 InitializeMacApp();
5496 #endif
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
5539 // never go away.
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();
5555 #endif
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",
5573 nullptr);
5575 appStartup = components::AppStartup::Service();
5576 NS_ENSURE_TRUE(appStartup, NS_ERROR_FAILURE);
5578 mDirProvider.DoStartup();
5580 #ifdef XP_WIN
5581 // It needs to be called on the main thread because it has to use
5582 // nsObserverService.
5583 EnsureWin32kInitialized();
5584 #endif
5586 // As FilePreferences need the profile directory, we must initialize right
5587 // here.
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
5598 line. */
5599 nsCOMPtr<nsIObserverService> obsService =
5600 mozilla::services::GetObserverService();
5601 if (obsService) {
5602 obsService->NotifyObservers(cmdLine, "command-line-startup", nullptr);
5606 #ifdef XP_WIN
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
5614 // PR_SetEnv.
5615 PR_SetEnv(saved.release());
5617 #endif
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.
5633 #ifdef XP_MACOSX
5634 bool lazyHiddenWindow = false;
5635 #else
5636 bool lazyHiddenWindow = true;
5637 #endif
5639 #ifdef MOZ_BACKGROUNDTASKS
5640 if (BackgroundTasks::IsBackgroundTaskMode()) {
5641 // Background tasks aren't going to load a chrome XUL document.
5642 lazyHiddenWindow = true;
5644 #endif
5646 if (!lazyHiddenWindow) {
5647 rv = appStartup->CreateHiddenWindow();
5648 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
5651 #ifdef XP_WIN
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)
5684 #endif
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());
5692 #endif
5694 #ifdef XP_MACOSX
5695 InitializeMacApp();
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);
5708 free(tempArgv);
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);
5718 # endif
5719 #endif
5721 nsCOMPtr<nsIObserverService> obsService =
5722 mozilla::services::GetObserverService();
5723 if (obsService)
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
5742 // proxy window.
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
5765 // available to us.
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 */
5775 #if defined(XP_WIN)
5776 LauncherResult<bool> isAdminWithoutUac = IsAdminWithoutUac();
5777 if (isAdminWithoutUac.isOk()) {
5778 Telemetry::ScalarSet(
5779 Telemetry::ScalarID::OS_ENVIRONMENT_IS_ADMIN_WITHOUT_UAC,
5780 isAdminWithoutUac.unwrap());
5782 #endif /* XP_WIN */
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
5796 // startup crash.
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);
5813 #endif
5816 rv = appStartup->Run();
5817 if (NS_FAILED(rv)) {
5818 NS_ERROR("failed to run appstartup");
5819 gLogConsoleErrors = true;
5823 return rv;
5826 #if defined(MOZ_WIDGET_ANDROID)
5827 static already_AddRefed<nsIFile> GreOmniPath(int argc, char** argv) {
5828 nsresult rv;
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");
5835 return nullptr;
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");
5844 return nullptr;
5847 return greOmni.forget();
5849 #endif
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) {
5857 gArgc = argc;
5858 gArgv = argv;
5860 ScopedLogging log;
5862 mozilla::LogModule::Init(gArgc, gArgv);
5864 #ifndef XP_LINUX
5865 NS_SetCurrentThreadName("MainThread");
5866 #endif
5868 AUTO_BASE_PROFILER_LABEL("XREMain::XRE_main (around Gecko Profiler)", OTHER);
5869 AUTO_PROFILER_INIT;
5870 AUTO_PROFILER_LABEL("XREMain::XRE_main", OTHER);
5872 #ifdef XP_MACOSX
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();
5877 #endif
5879 #ifdef MOZ_CODE_COVERAGE
5880 CodeCoverageHandler::Init();
5881 #endif
5883 nsresult rv = NS_OK;
5885 if (aConfig.appData) {
5886 mAppData = MakeUnique<XREAppData>(*aConfig.appData);
5887 } else {
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);
5893 return 1;
5896 mAppData = MakeUnique<XREAppData>();
5897 rv = XRE_ParseAppData(appini, *mAppData);
5898 if (NS_FAILED(rv)) {
5899 Output(true, "Couldn't read application.ini");
5900 return 1;
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);
5927 if (!greDir) {
5928 return 2;
5930 #else
5931 rv = binFile->GetParent(getter_AddRefs(greDir));
5932 if (NS_FAILED(rv)) return 2;
5933 #endif
5935 #ifdef XP_MACOSX
5936 nsCOMPtr<nsIFile> parent;
5937 greDir->GetParent(getter_AddRefs(parent));
5938 greDir = parent.forget();
5939 greDir->AppendNative("Resources"_ns);
5940 #endif
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;
5951 #else
5952 if (aConfig.appData && aConfig.appDataPath) {
5953 mAppData->xreDirectory->Clone(getter_AddRefs(mAppData->directory));
5954 mAppData->directory->AppendNative(nsDependentCString(aConfig.appDataPath));
5956 #endif
5958 if (!mAppData->directory) {
5959 mAppData->directory = mAppData->xreDirectory;
5962 #if defined(XP_WIN)
5963 # if defined(MOZ_SANDBOX)
5964 mAppData->sandboxBrokerServices = aConfig.sandboxBrokerServices;
5965 # endif // defined(MOZ_SANDBOX)
5968 DebugOnly<bool> result = WindowsBCryptInitialization();
5969 MOZ_ASSERT(result);
5972 # if defined(_M_IX86) || defined(_M_X64)
5974 DebugOnly<bool> result = WindowsMsctfInitialization();
5975 MOZ_ASSERT(result);
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();
5987 return NS_OK;
5990 mozilla::AutoIOInterposer ioInterposerGuard;
5991 ioInterposerGuard.Init();
5993 #if defined(XP_WIN)
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;
5998 #endif
6000 // init
6001 bool exit = false;
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 {
6007 if (mProfLD) {
6008 nsCOMPtr<nsIFile> crashFile;
6009 MOZ_TRY_VAR(crashFile, GetIncompleteStartupFile(mProfLD));
6010 crashFile->Remove(false);
6012 return NS_OK;
6015 // startup
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()
6029 #endif
6031 Output(
6032 true,
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);
6040 // run!
6041 rv = XRE_mainRun();
6042 if (rv == NS_ERROR_OMNIJAR_OR_DIR_MISSING) {
6043 if (XRE_IsParentProcess()
6044 #ifdef MOZ_BACKGROUNDTASKS
6045 && !mozilla::BackgroundTasks::IsBackgroundTaskMode()
6046 #endif
6048 Output(true,
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");
6061 #ifdef MOZ_X11
6062 XRE_CleanupX11ErrorHandler();
6063 #endif
6065 #ifdef MOZ_INSTRUMENT_EVENT_LOOP
6066 mozilla::ShutdownEventTracing();
6067 #endif
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()) {
6095 # ifdef MOZ_WAYLAND
6096 WaylandDisplayRelease();
6097 gWaylandProxy = nullptr;
6098 # endif
6100 #endif
6102 mozilla::AppShutdown::MaybeDoRestart();
6104 XRE_DeinitCommandLine();
6106 if (NS_FAILED(rv)) {
6107 return 1;
6109 return mozilla::AppShutdown::GetExitCode();
6112 void XRE_StopLateWriteChecks(void) { mozilla::StopLateWriteChecks(); }
6114 int XRE_main(int argc, char* argv[], const BootstrapConfig& aConfig) {
6115 XREMain main;
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();
6123 #endif
6124 return result;
6127 nsresult XRE_InitCommandLine(int aArgc, char* aArgv[]) {
6128 nsresult rv = NS_OK;
6130 #if defined(XP_WIN)
6131 CommandLine::Init(aArgc, aArgv);
6132 #else
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) {
6149 if (aArgv[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]);
6158 delete[] canonArgs;
6159 #endif
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.
6165 if (gAppData) {
6166 nsCOMPtr<nsIFile> greOmni = gAppData->xreDirectory;
6167 if (!greOmni) {
6168 return NS_ERROR_FAILURE;
6170 mozilla::Omnijar::Init(greOmni, greOmni);
6172 #endif
6174 return rv;
6177 nsresult XRE_DeinitCommandLine() {
6178 nsresult rv = NS_OK;
6180 CommandLine::Terminate();
6182 return rv;
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();
6197 #else
6198 return XRE_IsParentProcess() && BrowserTabsRemoteAutostart();
6199 #endif
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:
6216 return false;
6217 case GeckoProcessType_Utility: {
6218 # if defined(XP_WIN)
6219 auto upc = mozilla::ipc::UtilityProcessChild::Get();
6220 MOZ_ASSERT(upc);
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;
6227 # else
6228 return false;
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();
6236 default:
6237 return true;
6241 namespace mozilla {
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) {
6248 return 1;
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) {
6261 #ifdef XP_WIN
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);
6272 #endif
6274 #ifdef XP_WIN
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);
6289 #endif
6291 InstallSignalHandlers(progname);
6293 // Unbuffer stdout, needed for tinderbox tests.
6294 setbuf(stdout, 0);
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;
6313 #ifdef XP_WIN
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
6324 default:
6325 return BinPathType::PluginContainer;
6327 #else
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;
6333 #endif
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);
6358 # ifdef XP_WIN
6359 nsAutoString nspathW;
6360 rv = dir->GetPath(nspathW);
6361 NS_ConvertUTF16toUTF8 nspath(nspathW);
6362 # else
6363 nsAutoCString nspath;
6364 rv = dir->GetNativePath(nspath);
6365 # endif
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());
6372 #endif