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/. */
5
6 #include "mozilla/dom/ContentParent.h"
7 #include "mozilla/dom/ContentChild.h"
8 #include "mozilla/ipc/GeckoChildProcessHost.h"
9
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/Likely.h"
20 #include "mozilla/MemoryChecking.h"
21 #include "mozilla/Poison.h"
22 #include "mozilla/Preferences.h"
23 #include "mozilla/Printf.h"
24 #include "mozilla/ResultExtensions.h"
25 #include "mozilla/ScopeExit.h"
26 #include "mozilla/StaticPrefs_browser.h"
27 #include "mozilla/StaticPrefs_fission.h"
28 #include "mozilla/StaticPrefs_webgl.h"
29 #include "mozilla/StaticPrefs_widget.h"
30 #include "mozilla/Telemetry.h"
31 #include "mozilla/Utf8.h"
32 #include "mozilla/intl/LocaleService.h"
33 #include "mozilla/JSONWriter.h"
34 #include "mozilla/gfx/gfxVars.h"
35 #include "BaseProfiler.h"
36
37 #include "nsAppRunner.h"
38 #include "mozilla/XREAppData.h"
39 #include "mozilla/Bootstrap.h"
40 #if defined(MOZ_UPDATER) && !defined(MOZ_WIDGET_ANDROID)
41 # include "nsUpdateDriver.h"
42 # include "nsUpdateSyncManager.h"
43 #endif
44 #include "ProfileReset.h"
45
46 #ifdef MOZ_INSTRUMENT_EVENT_LOOP
47 # include "EventTracer.h"
48 #endif
49
50 #ifdef XP_MACOSX
51 # include "nsVersionComparator.h"
52 # include "MacLaunchHelper.h"
53 # include "MacApplicationDelegate.h"
54 # include "MacAutoreleasePool.h"
55 # include "MacRunFromDmgUtils.h"
56 // these are needed for sysctl
57 # include <sys/types.h>
58 # include <sys/sysctl.h>
59 #endif
60
61 #include "prnetdb.h"
62 #include "prprf.h"
63 #include "prproces.h"
64 #include "prenv.h"
65 #include "prtime.h"
66
67 #include "nsIAppStartup.h"
68 #include "nsAppStartupNotifier.h"
69 #include "nsIMutableArray.h"
70 #include "nsCommandLine.h"
71 #include "nsIComponentRegistrar.h"
72 #include "nsIDialogParamBlock.h"
73 #include "mozilla/ModuleUtils.h"
74 #include "nsIIOService.h"
75 #include "nsIObserverService.h"
76 #include "nsINativeAppSupport.h"
77 #include "nsIPlatformInfo.h"
78 #include "nsIProcess.h"
79 #include "nsIProfileUnlocker.h"
80 #include "nsIPromptService.h"
81 #include "nsIPropertyBag2.h"
82 #include "nsIServiceManager.h"
83 #include "nsIStringBundle.h"
84 #include "nsISupportsPrimitives.h"
85 #include "nsIToolkitProfile.h"
86 #include "nsToolkitProfileService.h"
87 #include "nsIURI.h"
88 #include "nsIURL.h"
89 #include "nsIWindowCreator.h"
90 #include "nsIWindowWatcher.h"
91 #include "nsIXULAppInfo.h"
92 #include "nsIXULRuntime.h"
93 #include "nsPIDOMWindow.h"
94 #include "nsIWidget.h"
95 #include "nsAppShellCID.h"
96 #include "mozilla/dom/quota/QuotaManager.h"
97 #include "mozilla/scache/StartupCache.h"
98 #include "gfxPlatform.h"
99 #include "PDMFactory.h"
100 #ifdef XP_MACOSX
101 # include "gfxPlatformMac.h"
102 #endif
103
104 #include "mozilla/Unused.h"
105
106 #ifdef XP_WIN
107 # include "nsIWinAppHelper.h"
108 # include <windows.h>
109 # include <intrin.h>
110 # include <math.h>
111 # include "cairo/cairo-features.h"
112 # include "mozilla/PreXULSkeletonUI.h"
113 # include "mozilla/DllPrefetchExperimentRegistryInfo.h"
114 # include "mozilla/WindowsDllBlocklist.h"
115 # include "mozilla/WindowsProcessMitigations.h"
116 # include "mozilla/WinHeaderOnlyUtils.h"
117 # include "mozilla/mscom/ProcessRuntime.h"
118 # include "mozilla/mscom/ProfilerMarkers.h"
119 # include "mozilla/widget/AudioSession.h"
120 # include "WinTokenUtils.h"
121
122 # if defined(MOZ_LAUNCHER_PROCESS)
123 # include "mozilla/LauncherRegistryInfo.h"
124 # endif
125
126 # if defined(MOZ_DEFAULT_BROWSER_AGENT)
127 # include "nsIWindowsRegKey.h"
128 # endif
129
130 # ifndef PROCESS_DEP_ENABLE
131 # define PROCESS_DEP_ENABLE 0x1
132 # endif
133 #endif
134
135 #if defined(MOZ_SANDBOX)
136 # include "mozilla/SandboxSettings.h"
137 #endif
138
139 #ifdef ACCESSIBILITY
140 # include "nsAccessibilityService.h"
141 # if defined(XP_WIN)
142 # include "mozilla/a11y/Compatibility.h"
143 # include "mozilla/a11y/Platform.h"
144 # endif
145 #endif
146
147 #include "nsCRT.h"
148 #include "nsCOMPtr.h"
149 #include "nsDirectoryServiceDefs.h"
150 #include "nsDirectoryServiceUtils.h"
151 #include "nsEmbedCID.h"
152 #include "nsIDUtils.h"
153 #include "nsNetUtil.h"
154 #include "nsReadableUtils.h"
155 #include "nsXPCOM.h"
156 #include "nsXPCOMCIDInternal.h"
157 #include "nsString.h"
158 #include "nsPrintfCString.h"
159 #include "nsVersionComparator.h"
160
161 #include "nsAppDirectoryServiceDefs.h"
162 #include "nsXULAppAPI.h"
163 #include "nsXREDirProvider.h"
164
165 #include "nsINIParser.h"
166 #include "mozilla/Omnijar.h"
167 #include "mozilla/StartupTimeline.h"
168 #include "mozilla/LateWriteChecks.h"
169
170 #include <stdlib.h>
171 #include <locale.h>
172
173 #ifdef XP_UNIX
174 # include <errno.h>
175 # include <pwd.h>
176 # include <string.h>
177 # include <sys/resource.h>
178 # include <sys/stat.h>
179 # include <unistd.h>
180 #endif
181
182 #ifdef XP_WIN
183 # include <process.h>
184 # include <shlobj.h>
185 # include "mozilla/WinDllServices.h"
186 # include "nsThreadUtils.h"
187 # include "WinUtils.h"
188 #endif
189
190 #ifdef XP_MACOSX
191 # include "nsILocalFileMac.h"
192 # include "nsCommandLineServiceMac.h"
193 #endif
194
195 // for X remote support
196 #if defined(MOZ_HAS_REMOTE)
197 # include "nsRemoteService.h"
198 #endif
199
200 #if defined(DEBUG) && defined(XP_WIN)
201 # include <malloc.h>
202 #endif
203
204 #if defined(XP_MACOSX)
205 # include <Carbon/Carbon.h>
206 #endif
207
208 #ifdef DEBUG
209 # include "mozilla/Logging.h"
210 #endif
211
212 #ifdef MOZ_JPROF
213 # include "jprof.h"
214 #endif
215
216 #include "nsExceptionHandler.h"
217 #include "nsICrashReporter.h"
218 #include "nsIPrefService.h"
219 #include "nsIMemoryInfoDumper.h"
220 #if defined(XP_LINUX) && !defined(ANDROID)
221 # include "mozilla/widget/LSBUtils.h"
222 #endif
223
224 #include "base/command_line.h"
225 #include "GTestRunner.h"
226
227 #ifdef MOZ_WIDGET_ANDROID
228 # include "mozilla/java/GeckoAppShellWrappers.h"
229 #endif
230
231 #if defined(MOZ_SANDBOX)
232 # if defined(XP_LINUX) && !defined(ANDROID)
233 # include "mozilla/SandboxInfo.h"
234 # elif defined(XP_WIN)
235 # include "sandboxBroker.h"
236 # include "sandboxPermissions.h"
237 # endif
238 #endif
239
240 #ifdef MOZ_CODE_COVERAGE
241 # include "mozilla/CodeCoverageHandler.h"
242 #endif
243
244 #include "SafeMode.h"
245
246 #ifdef MOZ_BACKGROUNDTASKS
247 # include "mozilla/BackgroundTasks.h"
248 # include "nsIPowerManagerService.h"
249 # include "nsIStringBundle.h"
250 #endif
251
252 extern uint32_t gRestartMode;
253 extern void InstallSignalHandlers(const char* ProgramName);
254
255 #define FILE_COMPATIBILITY_INFO "compatibility.ini"_ns
256 #define FILE_INVALIDATE_CACHES ".purgecaches"_ns
257 #define FILE_STARTUP_INCOMPLETE u".startup-incomplete"_ns
258
259 #if defined(MOZ_BLOCK_PROFILE_DOWNGRADE) || defined(MOZ_LAUNCHER_PROCESS) || \
260 defined(MOZ_DEFAULT_BROWSER_AGENT)
261 static const char kPrefHealthReportUploadEnabled[] =
262 "datareporting.healthreport.uploadEnabled";
263 #endif // defined(MOZ_BLOCK_PROFILE_DOWNGRADE) || defined(MOZ_LAUNCHER_PROCESS)
264 // || defined(MOZ_DEFAULT_BROWSER_AGENT)
265 #if defined(MOZ_DEFAULT_BROWSER_AGENT)
266 static const char kPrefDefaultAgentEnabled[] = "default-browser-agent.enabled";
267
268 static const char kPrefServicesSettingsServer[] = "services.settings.server";
269 static const char kPrefSecurityContentSignatureRootHash[] =
270 "security.content.signature.root_hash";
271 static const char kPrefSetDefaultBrowserUserChoicePref[] =
272 "browser.shell.setDefaultBrowserUserChoice";
273 #endif // defined(MOZ_DEFAULT_BROWSER_AGENT)
274
275 #if defined(XP_WIN)
276 static const char kPrefThemeId[] = "extensions.activeThemeID";
277 static const char kPrefBrowserStartupBlankWindow[] =
278 "browser.startup.blankWindow";
279 static const char kPrefPreXulSkeletonUI[] = "browser.startup.preXulSkeletonUI";
280 #endif // defined(XP_WIN)
281
282 int gArgc;
283 char** gArgv;
284
285 static const char gToolkitVersion[] = MOZ_STRINGIFY(GRE_MILESTONE);
286 // The gToolkitBuildID global is defined to MOZ_BUILDID via gen_buildid.py
287 // in toolkit/library. See related comment in toolkit/library/moz.build.
288 extern const char gToolkitBuildID[];
289
290 static nsIProfileLock* gProfileLock;
291 #if defined(MOZ_HAS_REMOTE)
292 static nsRemoteService* gRemoteService;
293 #endif
294
295 int gRestartArgc;
296 char** gRestartArgv;
297
298 // If gRestartedByOS is set, we were automatically restarted by the OS.
299 bool gRestartedByOS = false;
300
301 bool gIsGtest = false;
302
303 nsString gAbsoluteArgv0Path;
304
305 #if defined(XP_WIN)
306 nsString gProcessStartupShortcut;
307 #endif
308
309 #if defined(MOZ_WIDGET_GTK)
310 # include <glib.h>
311 # if defined(DEBUG) || defined(NS_BUILD_REFCNT_LOGGING)
312 # define CLEANUP_MEMORY 1
313 # define PANGO_ENABLE_BACKEND
314 # include <pango/pangofc-fontmap.h>
315 # endif
316 # include "mozilla/WidgetUtilsGtk.h"
317 # include <gtk/gtk.h>
318 # ifdef MOZ_WAYLAND
319 # include <gdk/gdkwayland.h>
320 # include "mozilla/widget/nsWaylandDisplay.h"
321 # endif
322 # ifdef MOZ_X11
323 # include <gdk/gdkx.h>
324 # endif /* MOZ_X11 */
325 # include <fontconfig/fontconfig.h>
326 #endif
327 #include "BinaryPath.h"
328
329 #ifdef MOZ_LINKER
330 extern "C" MFBT_API bool IsSignalHandlingBroken();
331 #endif
332
333 #ifdef FUZZING
334 # include "FuzzerRunner.h"
335
336 namespace mozilla {
337 FuzzerRunner* fuzzerRunner = 0;
338 } // namespace mozilla
339
340 # ifdef LIBFUZZER
XRE_LibFuzzerSetDriver(LibFuzzerDriver aDriver)341 void XRE_LibFuzzerSetDriver(LibFuzzerDriver aDriver) {
342 mozilla::fuzzerRunner->setParams(aDriver);
343 }
344 # endif
345 #endif // FUZZING
346
347 // Undo X11/X.h's definition of None
348 #undef None
349
350 namespace mozilla {
351 int (*RunGTest)(int*, char**) = 0;
352
RunningGTest()353 bool RunningGTest() { return RunGTest; }
354 } // namespace mozilla
355
356 using namespace mozilla;
357 using namespace mozilla::widget;
358 using namespace mozilla::startup;
359 using mozilla::Unused;
360 using mozilla::dom::ContentChild;
361 using mozilla::dom::ContentParent;
362 using mozilla::dom::quota::QuotaManager;
363 using mozilla::intl::LocaleService;
364 using mozilla::scache::StartupCache;
365
366 // Save the given word to the specified environment variable.
SaveWordToEnv(const char * name,const nsACString & word)367 static void MOZ_NEVER_INLINE SaveWordToEnv(const char* name,
368 const nsACString& word) {
369 char* expr =
370 Smprintf("%s=%s", name, PromiseFlatCString(word).get()).release();
371 if (expr) PR_SetEnv(expr);
372 // We intentionally leak |expr| here since it is required by PR_SetEnv.
373 }
374
375 // Save the path of the given file to the specified environment variable.
SaveFileToEnv(const char * name,nsIFile * file)376 static void SaveFileToEnv(const char* name, nsIFile* file) {
377 #ifdef XP_WIN
378 nsAutoString path;
379 file->GetPath(path);
380 SetEnvironmentVariableW(NS_ConvertASCIItoUTF16(name).get(), path.get());
381 #else
382 nsAutoCString path;
383 file->GetNativePath(path);
384 SaveWordToEnv(name, path);
385 #endif
386 }
387
388 static bool gIsExpectedExit = false;
389
MozExpectedExit()390 void MozExpectedExit() { gIsExpectedExit = true; }
391
392 /**
393 * Runs atexit() to catch unexpected exit from 3rd party libraries like the
394 * Intel graphics driver calling exit in an error condition. When they
395 * call exit() to report an error we won't shutdown correctly and wont catch
396 * the issue with our crash reporter.
397 */
UnexpectedExit()398 static void UnexpectedExit() {
399 if (!gIsExpectedExit) {
400 gIsExpectedExit = true; // Don't risk re-entrency issues when crashing.
401 MOZ_CRASH("Exit called by third party code.");
402 }
403 }
404
405 /**
406 * Output a string to the user. This method is really only meant to be used to
407 * output last-ditch error messages designed for developers NOT END USERS.
408 *
409 * @param isError
410 * Pass true to indicate severe errors.
411 * @param fmt
412 * printf-style format string followed by arguments.
413 */
Output(bool isError,const char * fmt,...)414 static MOZ_FORMAT_PRINTF(2, 3) void Output(bool isError, const char* fmt, ...) {
415 va_list ap;
416 va_start(ap, fmt);
417
418 #if defined(XP_WIN) && !MOZ_WINCONSOLE
419 SmprintfPointer msg = mozilla::Vsmprintf(fmt, ap);
420 if (msg) {
421 UINT flags = MB_OK;
422 if (isError)
423 flags |= MB_ICONERROR;
424 else
425 flags |= MB_ICONINFORMATION;
426
427 wchar_t wide_msg[1024];
428 MultiByteToWideChar(CP_ACP, 0, msg.get(), -1, wide_msg,
429 sizeof(wide_msg) / sizeof(wchar_t));
430
431 MessageBoxW(nullptr, wide_msg, L"XULRunner", flags);
432 }
433 #elif defined(MOZ_WIDGET_ANDROID)
434 SmprintfPointer msg = mozilla::Vsmprintf(fmt, ap);
435 if (msg) {
436 __android_log_print(isError ? ANDROID_LOG_ERROR : ANDROID_LOG_INFO,
437 "GeckoRuntime", "%s", msg.get());
438 }
439 #else
440 vfprintf(stderr, fmt, ap);
441 #endif
442
443 va_end(ap);
444 }
445
446 /**
447 * Check for a commandline flag. If the flag takes a parameter, the
448 * parameter is returned in aParam. Flags may be in the form -arg or
449 * --arg (or /arg on win32).
450 *
451 * @param aArg the parameter to check. Must be lowercase.
452 * @param aParam if non-null, the -arg <data> will be stored in this pointer.
453 * This is *not* allocated, but rather a pointer to the argv data.
454 * @param aFlags flags @see CheckArgFlag
455 */
CheckArg(const char * aArg,const char ** aParam=nullptr,CheckArgFlag aFlags=CheckArgFlag::RemoveArg)456 static ArgResult CheckArg(const char* aArg, const char** aParam = nullptr,
457 CheckArgFlag aFlags = CheckArgFlag::RemoveArg) {
458 MOZ_ASSERT(gArgv, "gArgv must be initialized before CheckArg()");
459 return CheckArg(gArgc, gArgv, aArg, aParam, aFlags);
460 }
461
462 /**
463 * Check for a commandline flag. Ignore data that's passed in with the flag.
464 * Flags may be in the form -arg or --arg (or /arg on win32).
465 * Will not remove flag if found.
466 *
467 * @param aArg the parameter to check. Must be lowercase.
468 */
CheckArgExists(const char * aArg)469 static ArgResult CheckArgExists(const char* aArg) {
470 return CheckArg(aArg, nullptr, CheckArgFlag::None);
471 }
472
473 bool gSafeMode = false;
474 bool gFxREmbedded = false;
475
476 enum E10sStatus {
477 kE10sEnabledByDefault,
478 kE10sDisabledByUser,
479 kE10sForceDisabled,
480 };
481
482 static bool gBrowserTabsRemoteAutostart = false;
483 static E10sStatus gBrowserTabsRemoteStatus;
484 static bool gBrowserTabsRemoteAutostartInitialized = false;
485
486 namespace mozilla {
487
BrowserTabsRemoteAutostart()488 bool BrowserTabsRemoteAutostart() {
489 if (gBrowserTabsRemoteAutostartInitialized) {
490 return gBrowserTabsRemoteAutostart;
491 }
492 gBrowserTabsRemoteAutostartInitialized = true;
493
494 // If we're not in the parent process, we are running E10s.
495 if (!XRE_IsParentProcess()) {
496 gBrowserTabsRemoteAutostart = true;
497 return gBrowserTabsRemoteAutostart;
498 }
499
500 #if defined(MOZILLA_OFFICIAL) && MOZ_BUILD_APP_IS_BROWSER
501 bool allowSingleProcessOutsideAutomation = false;
502 #else
503 bool allowSingleProcessOutsideAutomation = true;
504 #endif
505
506 E10sStatus status = kE10sEnabledByDefault;
507 // We use "are non-local connections disabled" as a proxy for
508 // "are we running some kind of automated test". It would be nicer to use
509 // xpc::IsInAutomation(), but that depends on some prefs being set, which
510 // they are not in (at least) gtests (where we can't) and xpcshell.
511 // Long-term, hopefully we can make tests switch to environment variables
512 // to disable e10s and then we can get rid of this.
513 if (allowSingleProcessOutsideAutomation ||
514 xpc::AreNonLocalConnectionsDisabled()) {
515 bool optInPref =
516 Preferences::GetBool("browser.tabs.remote.autostart", true);
517
518 if (optInPref) {
519 gBrowserTabsRemoteAutostart = true;
520 } else {
521 status = kE10sDisabledByUser;
522 }
523 } else {
524 gBrowserTabsRemoteAutostart = true;
525 }
526
527 // Uber override pref for emergency blocking
528 if (gBrowserTabsRemoteAutostart) {
529 const char* forceDisable = PR_GetEnv("MOZ_FORCE_DISABLE_E10S");
530 #if defined(MOZ_WIDGET_ANDROID)
531 // We need this for xpcshell on Android
532 if (forceDisable && *forceDisable) {
533 #else
534 // The environment variable must match the application version to apply.
535 if (forceDisable && gAppData && !strcmp(forceDisable, gAppData->version)) {
536 #endif
537 gBrowserTabsRemoteAutostart = false;
538 status = kE10sForceDisabled;
539 }
540 }
541
542 // Disable MultiProcessing for DragonFly. Slowness and many crashes that require
543 // quite some debugging and investigation.
544 gBrowserTabsRemoteAutostart = false;
545 status = kE10sForceDisabled;
546
547 gBrowserTabsRemoteStatus = status;
548
549 return gBrowserTabsRemoteAutostart;
550 }
551
552 } // namespace mozilla
553
554 // Win32k Infrastructure ==============================================
555
556 // This bool tells us if we have initialized the following two statics
557 // upon startup.
558
559 static bool gWin32kInitialized = false;
560
561 // Win32k Lockdown for the current session is determined once, at startup,
562 // and then remains the same for the duration of the session.
563
564 static nsIXULRuntime::ContentWin32kLockdownState gWin32kStatus;
565
566 // The status of the win32k experiment. It is determined once, at startup,
567 // and then remains the same for the duration of the session.
568
569 static nsIXULRuntime::ExperimentStatus gWin32kExperimentStatus =
570 nsIXULRuntime::eExperimentStatusUnenrolled;
571
572 #ifdef XP_WIN
573 // The states for win32k lockdown can be generalized to:
574 // - User doesn't meet requirements (bad OS, webrender, remotegl) aka
575 // PersistentRequirement
576 // - User has Safe Mode enabled, Win32k Disabled by Env Var, or E10S disabled
577 // by Env Var aka TemporaryRequirement
578 // - User has set the win32k pref to something non-default aka NonDefaultPref
579 // - User has been enrolled in the experiment and does what it says aka
580 // Enrolled
581 // - User does the default aka Default
582 //
583 // We expect the below behvaior. In the code, there may be references to these
584 // behaviors (e.g. [A]) but not always.
585 //
586 // [A] Becoming enrolled in the experiment while NonDefaultPref disqualifies
587 // you upon next browser start
588 // [B] Becoming enrolled in the experiment while PersistentRequirement
589 // disqualifies you upon next browser start
590 // [C] Becoming enrolled in the experiment while TemporaryRequirement does not
591 // disqualify you
592 // [D] Becoming enrolled in the experiment will only take effect after restart
593 // [E] While enrolled, becoming PersistentRequirement will not disqualify you
594 // until browser restart, but if the state is present at browser start,
595 // will disqualify you. Additionally, it will not affect the session value
596 // of gWin32kStatus.
597 // XXX(bobowen): I hope both webrender and wbgl.out-of-process require a
598 // restart to take effect!
599 // [F] While enrolled, becoming NonDefaultPref will disqualify you upon next
600 // browser start
601 // [G] While enrolled, becoming TemporaryRequirement will _not_ disqualify you,
602 // but the session status will prevent win32k lockdown from taking effect.
603
604 // The win32k pref
605 static const char kPrefWin32k[] = "security.sandbox.content.win32k-disable";
606
607 // The current enrollment status as controlled by Normandy. This value is only
608 // stored in the default preference branch, and is not persisted across
609 // sessions by the preference service. It therefore isn't available early
610 // enough at startup, and needs to be synced to a preference in the user
611 // branch which is persisted across sessions.
612 static const char kPrefWin32kExperimentEnrollmentStatus[] =
613 "security.sandbox.content.win32k-experiment.enrollmentStatus";
614
615 // The enrollment status to be used at browser startup. This automatically
616 // synced from the above enrollmentStatus preference whenever the latter is
617 // changed. We reused the Fission experiment enum - it can have any of the
618 // values defined in the `nsIXULRuntime_ExperimentStatus` enum _except_ rollout.
619 // Meanings are documented in the declaration of
620 // `nsIXULRuntime.fissionExperimentStatus`
621 static const char kPrefWin32kExperimentStartupEnrollmentStatus[] =
622 "security.sandbox.content.win32k-experiment.startupEnrollmentStatus";
623
624 namespace mozilla {
625
Win32kExperimentEnrolled()626 bool Win32kExperimentEnrolled() {
627 MOZ_ASSERT(XRE_IsParentProcess());
628 return gWin32kExperimentStatus == nsIXULRuntime::eExperimentStatusControl ||
629 gWin32kExperimentStatus == nsIXULRuntime::eExperimentStatusTreatment;
630 }
631
632 } // namespace mozilla
633
Win32kRequirementsUnsatisfied(nsIXULRuntime::ContentWin32kLockdownState aStatus)634 static bool Win32kRequirementsUnsatisfied(
635 nsIXULRuntime::ContentWin32kLockdownState aStatus) {
636 return aStatus == nsIXULRuntime::ContentWin32kLockdownState::
637 OperatingSystemNotSupported ||
638 aStatus ==
639 nsIXULRuntime::ContentWin32kLockdownState::MissingWebRender ||
640 aStatus ==
641 nsIXULRuntime::ContentWin32kLockdownState::MissingRemoteWebGL ||
642 aStatus ==
643 nsIXULRuntime::ContentWin32kLockdownState::DecodersArentRemote;
644 }
645
Win32kExperimentDisqualify()646 static void Win32kExperimentDisqualify() {
647 MOZ_ASSERT(XRE_IsParentProcess());
648 Preferences::SetUint(kPrefWin32kExperimentEnrollmentStatus,
649 nsIXULRuntime::eExperimentStatusDisqualified);
650 }
651
OnWin32kEnrollmentStatusChanged(const char * aPref,void * aData)652 static void OnWin32kEnrollmentStatusChanged(const char* aPref, void* aData) {
653 auto newStatusInt =
654 Preferences::GetUint(kPrefWin32kExperimentEnrollmentStatus,
655 nsIXULRuntime::eExperimentStatusUnenrolled);
656 auto newStatus = newStatusInt < nsIXULRuntime::eExperimentStatusCount
657 ? nsIXULRuntime::ExperimentStatus(newStatusInt)
658 : nsIXULRuntime::eExperimentStatusDisqualified;
659
660 // Set the startup pref for next browser start [D]
661 Preferences::SetUint(kPrefWin32kExperimentStartupEnrollmentStatus, newStatus);
662 }
663
664 namespace {
665 // This observer is notified during `profile-before-change`, and ensures that
666 // the experiment enrollment status is synced over before the browser shuts
667 // down, even if it was not modified since win32k was initialized.
668 class Win32kEnrollmentStatusShutdownObserver final : public nsIObserver {
669 public:
670 NS_DECL_ISUPPORTS
671
Observe(nsISupports * aSubject,const char * aTopic,const char16_t * aData)672 NS_IMETHOD Observe(nsISupports* aSubject, const char* aTopic,
673 const char16_t* aData) override {
674 MOZ_ASSERT(!strcmp("profile-before-change", aTopic));
675 OnWin32kEnrollmentStatusChanged(kPrefWin32kExperimentEnrollmentStatus,
676 nullptr);
677 return NS_OK;
678 }
679
680 private:
681 ~Win32kEnrollmentStatusShutdownObserver() = default;
682 };
683 NS_IMPL_ISUPPORTS(Win32kEnrollmentStatusShutdownObserver, nsIObserver)
684 } // namespace
685
OnWin32kChanged(const char * aPref,void * aData)686 static void OnWin32kChanged(const char* aPref, void* aData) {
687 // If we're actively enrolled in the Win32k experiment, disqualify the user
688 // from the experiment if the Win32k pref is modified. [F]
689 if (Win32kExperimentEnrolled() && Preferences::HasUserValue(kPrefWin32k)) {
690 Win32kExperimentDisqualify();
691 }
692 }
693
694 #endif // XP_WIN
695
696 namespace mozilla {
697 void EnsureWin32kInitialized();
698 }
699
GetLiveWin32kLockdownState()700 nsIXULRuntime::ContentWin32kLockdownState GetLiveWin32kLockdownState() {
701 #ifdef XP_WIN
702
703 // HasUserValue The Pref functions can only be called on main thread
704 MOZ_ASSERT(NS_IsMainThread());
705 mozilla::EnsureWin32kInitialized();
706 gfx::gfxVars::Initialize();
707
708 if (gSafeMode) {
709 return nsIXULRuntime::ContentWin32kLockdownState::DisabledBySafeMode;
710 }
711
712 if (EnvHasValue("MOZ_ENABLE_WIN32K")) {
713 return nsIXULRuntime::ContentWin32kLockdownState::DisabledByEnvVar;
714 }
715
716 if (!mozilla::BrowserTabsRemoteAutostart()) {
717 return nsIXULRuntime::ContentWin32kLockdownState::DisabledByE10S;
718 }
719
720 // Win32k lockdown is available on Win8+, but we are initially limiting it to
721 // Windows 10 v1709 (build 16299) or later. Before this COM initialization
722 // currently fails if user32.dll has loaded before it is called.
723 if (!IsWin10FallCreatorsUpdateOrLater()) {
724 return nsIXULRuntime::ContentWin32kLockdownState::
725 OperatingSystemNotSupported;
726 }
727
728 // Win32k Lockdown requires WebRender, but WR is not currently guaranteed
729 // on all computers. It can also fail to initialize and fallback to
730 // non-WR render path.
731 //
732 // We don't want a situation where "Win32k Lockdown + No WR" occurs
733 // without the user explicitly requesting unsupported behavior.
734 if (!gfx::gfxVars::UseWebRender()) {
735 return nsIXULRuntime::ContentWin32kLockdownState::MissingWebRender;
736 }
737
738 // Non-native theming is required as well
739 if (!StaticPrefs::widget_non_native_theme_enabled()) {
740 return nsIXULRuntime::ContentWin32kLockdownState::MissingNonNativeTheming;
741 }
742
743 // Win32k Lockdown requires Remote WebGL, but it may be disabled on
744 // certain hardware or virtual machines.
745 if (!gfx::gfxVars::AllowWebglOop() || !StaticPrefs::webgl_out_of_process()) {
746 return nsIXULRuntime::ContentWin32kLockdownState::MissingRemoteWebGL;
747 }
748
749 // Some (not sure exactly which) decoders are not compatible
750 if (!PDMFactory::AllDecodersAreRemote()) {
751 return nsIXULRuntime::ContentWin32kLockdownState::DecodersArentRemote;
752 }
753
754 bool prefSetByUser =
755 Preferences::HasUserValue("security.sandbox.content.win32k-disable");
756 bool prefValue = Preferences::GetBool(
757 "security.sandbox.content.win32k-disable", false, PrefValueKind::User);
758 bool defaultValue = Preferences::GetBool(
759 "security.sandbox.content.win32k-disable", false, PrefValueKind::Default);
760
761 if (prefSetByUser) {
762 if (prefValue) {
763 return nsIXULRuntime::ContentWin32kLockdownState::EnabledByUserPref;
764 } else {
765 return nsIXULRuntime::ContentWin32kLockdownState::DisabledByUserPref;
766 }
767 }
768
769 if (gWin32kExperimentStatus ==
770 nsIXULRuntime::ExperimentStatus::eExperimentStatusControl) {
771 return nsIXULRuntime::ContentWin32kLockdownState::DisabledByControlGroup;
772 } else if (gWin32kExperimentStatus ==
773 nsIXULRuntime::ExperimentStatus::eExperimentStatusTreatment) {
774 return nsIXULRuntime::ContentWin32kLockdownState::EnabledByTreatmentGroup;
775 }
776
777 if (defaultValue) {
778 return nsIXULRuntime::ContentWin32kLockdownState::EnabledByDefault;
779 } else {
780 return nsIXULRuntime::ContentWin32kLockdownState::DisabledByDefault;
781 }
782
783 #else
784
785 return nsIXULRuntime::ContentWin32kLockdownState::OperatingSystemNotSupported;
786
787 #endif
788 }
789
790 namespace mozilla {
791
EnsureWin32kInitialized()792 void EnsureWin32kInitialized() {
793 if (gWin32kInitialized) {
794 return;
795 }
796 gWin32kInitialized = true;
797
798 #ifdef XP_WIN
799
800 // Initialize the Win32k experiment, configuring win32k's
801 // default, before checking other overrides. This allows opting-out of a
802 // Win32k experiment through about:preferences or about:config from a
803 // safemode session.
804 uint32_t experimentRaw =
805 Preferences::GetUint(kPrefWin32kExperimentStartupEnrollmentStatus,
806 nsIXULRuntime::eExperimentStatusUnenrolled);
807 gWin32kExperimentStatus =
808 experimentRaw < nsIXULRuntime::eExperimentStatusCount
809 ? nsIXULRuntime::ExperimentStatus(experimentRaw)
810 : nsIXULRuntime::eExperimentStatusDisqualified;
811
812 // Watch the experiment enrollment status pref to detect experiment
813 // disqualification, and ensure it is propagated for the next restart.
814 Preferences::RegisterCallback(&OnWin32kEnrollmentStatusChanged,
815 kPrefWin32kExperimentEnrollmentStatus);
816 if (nsCOMPtr<nsIObserverService> observerService =
817 mozilla::services::GetObserverService()) {
818 nsCOMPtr<nsIObserver> shutdownObserver =
819 new Win32kEnrollmentStatusShutdownObserver();
820 observerService->AddObserver(shutdownObserver, "profile-before-change",
821 false);
822 }
823
824 // If the user no longer qualifies because they edited a required pref, check
825 // that. [B] [E]
826 auto tmpStatus = GetLiveWin32kLockdownState();
827 if (Win32kExperimentEnrolled() && Win32kRequirementsUnsatisfied(tmpStatus)) {
828 Win32kExperimentDisqualify();
829 gWin32kExperimentStatus = nsIXULRuntime::eExperimentStatusDisqualified;
830 }
831
832 // If the user has overridden an active experiment by setting a user value for
833 // "security.sandbox.content.win32k-disable", disqualify the user from the
834 // experiment. [A] [F]
835 if (Preferences::HasUserValue(kPrefWin32k) && Win32kExperimentEnrolled()) {
836 Win32kExperimentDisqualify();
837 gWin32kExperimentStatus = nsIXULRuntime::eExperimentStatusDisqualified;
838 }
839
840 // Unlike Fission, we do not configure the default branch based on experiment
841 // enrollment status. Instead we check the startupEnrollmentPref in
842 // GetContentWin32kLockdownState()
843
844 Preferences::RegisterCallback(&OnWin32kChanged, kPrefWin32k);
845
846 // Set the state
847 gWin32kStatus = GetLiveWin32kLockdownState();
848
849 #else
850 gWin32kStatus =
851 nsIXULRuntime::ContentWin32kLockdownState::OperatingSystemNotSupported;
852 gWin32kExperimentStatus = nsIXULRuntime::eExperimentStatusUnenrolled;
853
854 #endif // XP_WIN
855 }
856
GetWin32kLockdownState()857 nsIXULRuntime::ContentWin32kLockdownState GetWin32kLockdownState() {
858 #ifdef XP_WIN
859
860 mozilla::EnsureWin32kInitialized();
861 return gWin32kStatus;
862
863 #else
864
865 return nsIXULRuntime::ContentWin32kLockdownState::OperatingSystemNotSupported;
866
867 #endif
868 }
869
870 } // namespace mozilla
871
872 // End Win32k Infrastructure ==========================================
873
874 // Fission Infrastructure =============================================
875
876 // Fission enablement for the current session is determined once, at startup,
877 // and then remains the same for the duration of the session.
878 //
879 // The following factors determine whether or not Fission is enabled for a
880 // session, in order of precedence:
881 //
882 // - Safe mode: In safe mode, Fission is never enabled.
883 //
884 // - The MOZ_FORCE_ENABLE_FISSION environment variable: If set to any value,
885 // Fission will be enabled.
886 //
887 // - The 'fission.autostart' preference, if it has been configured by the user.
888 static const char kPrefFissionAutostart[] = "fission.autostart";
889 //
890 // - The fission experiment enrollment status set during the previous run, which
891 // is controlled by the following preferences:
892 //
893 // The current enrollment status as controlled by Normandy. This value is only
894 // stored in the default preference branch, and is not persisted across
895 // sessions by the preference service. It therefore isn't available early
896 // enough at startup, and needs to be synced to a preference in the user
897 // branch which is persisted across sessions.
898 static const char kPrefFissionExperimentEnrollmentStatus[] =
899 "fission.experiment.enrollmentStatus";
900 //
901 // The enrollment status to be used at browser startup. This automatically
902 // synced from the above enrollmentStatus preference whenever the latter is
903 // changed. It can have any of the values defined in the
904 // `nsIXULRuntime_ExperimentStatus` enum. Meanings are documented in
905 // the declaration of `nsIXULRuntime.fissionExperimentStatus`
906 static const char kPrefFissionExperimentStartupEnrollmentStatus[] =
907 "fission.experiment.startupEnrollmentStatus";
908
909 // The computed FissionAutostart value for the session, read by content
910 // processes to initialize gFissionAutostart.
911 //
912 // This pref is locked, and only configured on the default branch, so should
913 // never be persisted in a profile.
914 static const char kPrefFissionAutostartSession[] = "fission.autostart.session";
915
916 static nsIXULRuntime::ExperimentStatus gFissionExperimentStatus =
917 nsIXULRuntime::eExperimentStatusUnenrolled;
918 static bool gFissionAutostart = false;
919 static bool gFissionAutostartInitialized = false;
920 static nsIXULRuntime::FissionDecisionStatus gFissionDecisionStatus;
921
922 namespace mozilla {
923
FissionExperimentEnrolled()924 bool FissionExperimentEnrolled() {
925 MOZ_ASSERT(XRE_IsParentProcess());
926 return gFissionExperimentStatus == nsIXULRuntime::eExperimentStatusControl ||
927 gFissionExperimentStatus ==
928 nsIXULRuntime::eExperimentStatusTreatment ||
929 gFissionExperimentStatus == nsIXULRuntime::eExperimentStatusRollout;
930 }
931
932 } // namespace mozilla
933
FissionExperimentDisqualify()934 static void FissionExperimentDisqualify() {
935 MOZ_ASSERT(XRE_IsParentProcess());
936 // Setting this pref's user value will be detected by Normandy, causing the
937 // client to be unenrolled from the experiment.
938 Preferences::SetUint(kPrefFissionExperimentEnrollmentStatus,
939 nsIXULRuntime::eExperimentStatusDisqualified);
940 }
941
OnFissionEnrollmentStatusChanged(const char * aPref,void * aData)942 static void OnFissionEnrollmentStatusChanged(const char* aPref, void* aData) {
943 Preferences::SetUint(
944 kPrefFissionExperimentStartupEnrollmentStatus,
945 Preferences::GetUint(kPrefFissionExperimentEnrollmentStatus,
946 nsIXULRuntime::eExperimentStatusUnenrolled));
947 }
948
949 namespace {
950 // This observer is notified during `profile-before-change`, and ensures that
951 // the experiment enrollment status is synced over before the browser shuts
952 // down, even if it was not modified since FissionAutostart was initialized.
953 class FissionEnrollmentStatusShutdownObserver final : public nsIObserver {
954 public:
955 NS_DECL_ISUPPORTS
956
Observe(nsISupports * aSubject,const char * aTopic,const char16_t * aData)957 NS_IMETHOD Observe(nsISupports* aSubject, const char* aTopic,
958 const char16_t* aData) override {
959 MOZ_ASSERT(!strcmp("profile-before-change", aTopic));
960 OnFissionEnrollmentStatusChanged(kPrefFissionExperimentEnrollmentStatus,
961 nullptr);
962 return NS_OK;
963 }
964
965 private:
966 ~FissionEnrollmentStatusShutdownObserver() = default;
967 };
968 NS_IMPL_ISUPPORTS(FissionEnrollmentStatusShutdownObserver, nsIObserver)
969 } // namespace
970
OnFissionAutostartChanged(const char * aPref,void * aData)971 static void OnFissionAutostartChanged(const char* aPref, void* aData) {
972 MOZ_ASSERT(FissionExperimentEnrolled());
973 if (Preferences::HasUserValue(kPrefFissionAutostart)) {
974 FissionExperimentDisqualify();
975 }
976 }
977
EnsureFissionAutostartInitialized()978 static void EnsureFissionAutostartInitialized() {
979 if (gFissionAutostartInitialized) {
980 return;
981 }
982 gFissionAutostartInitialized = true;
983
984 if (!XRE_IsParentProcess()) {
985 // This pref is configured for the current session by the parent process.
986 gFissionAutostart = Preferences::GetBool(kPrefFissionAutostartSession,
987 false, PrefValueKind::Default);
988 return;
989 }
990
991 // Initialize the fission experiment, configuring fission.autostart's
992 // default, before checking other overrides. This allows opting-out of a
993 // fission experiment through about:preferences or about:config from a
994 // safemode session.
995 uint32_t experimentRaw =
996 Preferences::GetUint(kPrefFissionExperimentStartupEnrollmentStatus,
997 nsIXULRuntime::eExperimentStatusUnenrolled);
998 gFissionExperimentStatus =
999 experimentRaw < nsIXULRuntime::eExperimentStatusCount
1000 ? nsIXULRuntime::ExperimentStatus(experimentRaw)
1001 : nsIXULRuntime::eExperimentStatusDisqualified;
1002
1003 // Watch the experiment enrollment status pref to detect experiment
1004 // disqualification, and ensure it is propagated for the next restart.
1005 Preferences::RegisterCallback(&OnFissionEnrollmentStatusChanged,
1006 kPrefFissionExperimentEnrollmentStatus);
1007 if (nsCOMPtr<nsIObserverService> observerService =
1008 mozilla::services::GetObserverService()) {
1009 nsCOMPtr<nsIObserver> shutdownObserver =
1010 new FissionEnrollmentStatusShutdownObserver();
1011 observerService->AddObserver(shutdownObserver, "profile-before-change",
1012 false);
1013 }
1014
1015 // If the user has overridden an active experiment by setting a user value for
1016 // "fission.autostart", disqualify the user from the experiment.
1017 if (Preferences::HasUserValue(kPrefFissionAutostart) &&
1018 FissionExperimentEnrolled()) {
1019 FissionExperimentDisqualify();
1020 gFissionExperimentStatus = nsIXULRuntime::eExperimentStatusDisqualified;
1021 }
1022
1023 // Configure the default branch for "fission.autostart" based on experiment
1024 // enrollment status.
1025 if (FissionExperimentEnrolled()) {
1026 bool isTreatment =
1027 gFissionExperimentStatus == nsIXULRuntime::eExperimentStatusTreatment ||
1028 gFissionExperimentStatus == nsIXULRuntime::eExperimentStatusRollout;
1029 Preferences::SetBool(kPrefFissionAutostart, isTreatment,
1030 PrefValueKind::Default);
1031 }
1032
1033 if (!BrowserTabsRemoteAutostart()) {
1034 gFissionAutostart = false;
1035 if (gBrowserTabsRemoteStatus == kE10sForceDisabled) {
1036 gFissionDecisionStatus = nsIXULRuntime::eFissionDisabledByE10sEnv;
1037 } else {
1038 gFissionDecisionStatus = nsIXULRuntime::eFissionDisabledByE10sOther;
1039 }
1040 } else if (gSafeMode) {
1041 gFissionAutostart = false;
1042 gFissionDecisionStatus = nsIXULRuntime::eFissionDisabledBySafeMode;
1043 } else if (EnvHasValue("MOZ_FORCE_ENABLE_FISSION")) {
1044 gFissionAutostart = true;
1045 gFissionDecisionStatus = nsIXULRuntime::eFissionEnabledByEnv;
1046 } else if (EnvHasValue("MOZ_FORCE_DISABLE_FISSION")) {
1047 gFissionAutostart = false;
1048 gFissionDecisionStatus = nsIXULRuntime::eFissionDisabledByEnv;
1049 } else {
1050 // NOTE: This will take into account changes to the default due to
1051 // `InitializeFissionExperimentStatus`.
1052 gFissionAutostart = Preferences::GetBool(kPrefFissionAutostart, false);
1053 if (gFissionExperimentStatus == nsIXULRuntime::eExperimentStatusControl) {
1054 gFissionDecisionStatus = nsIXULRuntime::eFissionExperimentControl;
1055 } else if (gFissionExperimentStatus ==
1056 nsIXULRuntime::eExperimentStatusTreatment) {
1057 gFissionDecisionStatus = nsIXULRuntime::eFissionExperimentTreatment;
1058 } else if (gFissionExperimentStatus ==
1059 nsIXULRuntime::eExperimentStatusRollout) {
1060 gFissionDecisionStatus = nsIXULRuntime::eFissionEnabledByRollout;
1061 } else if (Preferences::HasUserValue(kPrefFissionAutostart)) {
1062 gFissionDecisionStatus = gFissionAutostart
1063 ? nsIXULRuntime::eFissionEnabledByUserPref
1064 : nsIXULRuntime::eFissionDisabledByUserPref;
1065 } else {
1066 gFissionDecisionStatus = gFissionAutostart
1067 ? nsIXULRuntime::eFissionEnabledByDefault
1068 : nsIXULRuntime::eFissionDisabledByDefault;
1069 }
1070 }
1071
1072 // Content processes cannot run the same logic as we're running in the parent
1073 // process, as the current value of various preferences may have changed
1074 // between launches. Instead, the content process will read the default branch
1075 // of the locked `fission.autostart.session` preference to determine the value
1076 // determined by this method.
1077 Preferences::Unlock(kPrefFissionAutostartSession);
1078 Preferences::ClearUser(kPrefFissionAutostartSession);
1079 Preferences::SetBool(kPrefFissionAutostartSession, gFissionAutostart,
1080 PrefValueKind::Default);
1081 Preferences::Lock(kPrefFissionAutostartSession);
1082
1083 // If we're actively enrolled in the fission experiment, disqualify the user
1084 // from the experiment if the fission pref is modified.
1085 if (FissionExperimentEnrolled()) {
1086 Preferences::RegisterCallback(&OnFissionAutostartChanged,
1087 kPrefFissionAutostart);
1088 }
1089 }
1090
1091 namespace mozilla {
1092
FissionAutostart()1093 bool FissionAutostart() {
1094 EnsureFissionAutostartInitialized();
1095 return gFissionAutostart;
1096 }
1097
1098 } // namespace mozilla
1099
1100 // End Fission Infrastructure =========================================
1101
1102 namespace mozilla {
1103
SessionHistoryInParent()1104 bool SessionHistoryInParent() {
1105 return FissionAutostart() ||
1106 StaticPrefs::
1107 fission_sessionHistoryInParent_AtStartup_DoNotUseDirectly();
1108 }
1109
BFCacheInParent()1110 bool BFCacheInParent() {
1111 return SessionHistoryInParent() &&
1112 StaticPrefs::fission_bfcacheInParent_DoNotUseDirectly();
1113 }
1114
1115 } // namespace mozilla
1116
1117 /**
1118 * The nsXULAppInfo object implements nsIFactory so that it can be its own
1119 * singleton.
1120 */
1121 class nsXULAppInfo : public nsIXULAppInfo,
1122 #ifdef XP_WIN
1123 public nsIWinAppHelper,
1124 #endif
1125 public nsICrashReporter,
1126 public nsIFinishDumpingCallback,
1127 public nsIXULRuntime
1128
1129 {
1130 public:
1131 constexpr nsXULAppInfo() = default;
1132 NS_DECL_ISUPPORTS_INHERITED
1133 NS_DECL_NSIPLATFORMINFO
1134 NS_DECL_NSIXULAPPINFO
1135 NS_DECL_NSIXULRUNTIME
1136 NS_DECL_NSICRASHREPORTER
1137 NS_DECL_NSIFINISHDUMPINGCALLBACK
1138 #ifdef XP_WIN
1139 NS_DECL_NSIWINAPPHELPER
1140 #endif
1141 };
1142
1143 NS_INTERFACE_MAP_BEGIN(nsXULAppInfo)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports,nsIXULRuntime)1144 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXULRuntime)
1145 NS_INTERFACE_MAP_ENTRY(nsIXULRuntime)
1146 #ifdef XP_WIN
1147 NS_INTERFACE_MAP_ENTRY(nsIWinAppHelper)
1148 #endif
1149 NS_INTERFACE_MAP_ENTRY(nsICrashReporter)
1150 NS_INTERFACE_MAP_ENTRY(nsIFinishDumpingCallback)
1151 NS_INTERFACE_MAP_ENTRY(nsIPlatformInfo)
1152 NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIXULAppInfo,
1153 gAppData || XRE_IsContentProcess())
1154 NS_INTERFACE_MAP_END
1155
1156 NS_IMETHODIMP_(MozExternalRefCountType)
1157 nsXULAppInfo::AddRef() { return 1; }
1158
NS_IMETHODIMP_(MozExternalRefCountType)1159 NS_IMETHODIMP_(MozExternalRefCountType)
1160 nsXULAppInfo::Release() { return 1; }
1161
1162 NS_IMETHODIMP
GetVendor(nsACString & aResult)1163 nsXULAppInfo::GetVendor(nsACString& aResult) {
1164 if (XRE_IsContentProcess()) {
1165 ContentChild* cc = ContentChild::GetSingleton();
1166 aResult = cc->GetAppInfo().vendor;
1167 return NS_OK;
1168 }
1169 aResult.Assign(gAppData->vendor);
1170
1171 return NS_OK;
1172 }
1173
1174 NS_IMETHODIMP
GetName(nsACString & aResult)1175 nsXULAppInfo::GetName(nsACString& aResult) {
1176 if (XRE_IsContentProcess()) {
1177 ContentChild* cc = ContentChild::GetSingleton();
1178 aResult = cc->GetAppInfo().name;
1179 return NS_OK;
1180 }
1181
1182 #ifdef MOZ_WIDGET_ANDROID
1183 nsCString name = java::GeckoAppShell::GetAppName()->ToCString();
1184 aResult.Assign(std::move(name));
1185 #else
1186 aResult.Assign(gAppData->name);
1187 #endif
1188
1189 return NS_OK;
1190 }
1191
1192 NS_IMETHODIMP
GetID(nsACString & aResult)1193 nsXULAppInfo::GetID(nsACString& aResult) {
1194 if (XRE_IsContentProcess()) {
1195 ContentChild* cc = ContentChild::GetSingleton();
1196 aResult = cc->GetAppInfo().ID;
1197 return NS_OK;
1198 }
1199 aResult.Assign(gAppData->ID);
1200
1201 return NS_OK;
1202 }
1203
1204 NS_IMETHODIMP
GetVersion(nsACString & aResult)1205 nsXULAppInfo::GetVersion(nsACString& aResult) {
1206 if (XRE_IsContentProcess()) {
1207 ContentChild* cc = ContentChild::GetSingleton();
1208 aResult = cc->GetAppInfo().version;
1209 return NS_OK;
1210 }
1211 aResult.Assign(gAppData->version);
1212
1213 return NS_OK;
1214 }
1215
1216 NS_IMETHODIMP
GetPlatformVersion(nsACString & aResult)1217 nsXULAppInfo::GetPlatformVersion(nsACString& aResult) {
1218 aResult.Assign(gToolkitVersion);
1219
1220 return NS_OK;
1221 }
1222
1223 NS_IMETHODIMP
GetAppBuildID(nsACString & aResult)1224 nsXULAppInfo::GetAppBuildID(nsACString& aResult) {
1225 if (XRE_IsContentProcess()) {
1226 ContentChild* cc = ContentChild::GetSingleton();
1227 aResult = cc->GetAppInfo().buildID;
1228 return NS_OK;
1229 }
1230 aResult.Assign(gAppData->buildID);
1231
1232 return NS_OK;
1233 }
1234
1235 NS_IMETHODIMP
GetPlatformBuildID(nsACString & aResult)1236 nsXULAppInfo::GetPlatformBuildID(nsACString& aResult) {
1237 aResult.Assign(gToolkitBuildID);
1238
1239 return NS_OK;
1240 }
1241
1242 NS_IMETHODIMP
GetUAName(nsACString & aResult)1243 nsXULAppInfo::GetUAName(nsACString& aResult) {
1244 if (XRE_IsContentProcess()) {
1245 ContentChild* cc = ContentChild::GetSingleton();
1246 aResult = cc->GetAppInfo().UAName;
1247 return NS_OK;
1248 }
1249 aResult.Assign(gAppData->UAName);
1250
1251 return NS_OK;
1252 }
1253
1254 NS_IMETHODIMP
GetSourceURL(nsACString & aResult)1255 nsXULAppInfo::GetSourceURL(nsACString& aResult) {
1256 if (XRE_IsContentProcess()) {
1257 ContentChild* cc = ContentChild::GetSingleton();
1258 aResult = cc->GetAppInfo().sourceURL;
1259 return NS_OK;
1260 }
1261 aResult.Assign(gAppData->sourceURL);
1262
1263 return NS_OK;
1264 }
1265
1266 NS_IMETHODIMP
GetUpdateURL(nsACString & aResult)1267 nsXULAppInfo::GetUpdateURL(nsACString& aResult) {
1268 if (XRE_IsContentProcess()) {
1269 ContentChild* cc = ContentChild::GetSingleton();
1270 aResult = cc->GetAppInfo().updateURL;
1271 return NS_OK;
1272 }
1273 aResult.Assign(gAppData->updateURL);
1274
1275 return NS_OK;
1276 }
1277
1278 NS_IMETHODIMP
GetLogConsoleErrors(bool * aResult)1279 nsXULAppInfo::GetLogConsoleErrors(bool* aResult) {
1280 *aResult = gLogConsoleErrors;
1281 return NS_OK;
1282 }
1283
1284 NS_IMETHODIMP
SetLogConsoleErrors(bool aValue)1285 nsXULAppInfo::SetLogConsoleErrors(bool aValue) {
1286 gLogConsoleErrors = aValue;
1287 return NS_OK;
1288 }
1289
1290 NS_IMETHODIMP
GetInSafeMode(bool * aResult)1291 nsXULAppInfo::GetInSafeMode(bool* aResult) {
1292 *aResult = gSafeMode;
1293 return NS_OK;
1294 }
1295
1296 NS_IMETHODIMP
GetOS(nsACString & aResult)1297 nsXULAppInfo::GetOS(nsACString& aResult) {
1298 aResult.AssignLiteral(OS_TARGET);
1299 return NS_OK;
1300 }
1301
1302 NS_IMETHODIMP
GetXPCOMABI(nsACString & aResult)1303 nsXULAppInfo::GetXPCOMABI(nsACString& aResult) {
1304 #ifdef TARGET_XPCOM_ABI
1305 aResult.AssignLiteral(TARGET_XPCOM_ABI);
1306 return NS_OK;
1307 #else
1308 return NS_ERROR_NOT_AVAILABLE;
1309 #endif
1310 }
1311
1312 NS_IMETHODIMP
GetWidgetToolkit(nsACString & aResult)1313 nsXULAppInfo::GetWidgetToolkit(nsACString& aResult) {
1314 aResult.AssignLiteral(MOZ_WIDGET_TOOLKIT);
1315 return NS_OK;
1316 }
1317
1318 // Ensure that the GeckoProcessType enum, defined in xpcom/build/nsXULAppAPI.h,
1319 // is synchronized with the const unsigned longs defined in
1320 // xpcom/system/nsIXULRuntime.idl.
1321 #define GECKO_PROCESS_TYPE(enum_value, enum_name, string_name, proc_typename, \
1322 process_bin_type, procinfo_typename, \
1323 webidl_typename, allcaps_name) \
1324 static_assert(nsIXULRuntime::PROCESS_TYPE_##allcaps_name == \
1325 static_cast<int>(GeckoProcessType_##enum_name), \
1326 "GeckoProcessType in nsXULAppAPI.h not synchronized with " \
1327 "nsIXULRuntime.idl");
1328 #include "mozilla/GeckoProcessTypes.h"
1329 #undef GECKO_PROCESS_TYPE
1330
1331 // .. and ensure that that is all of them:
1332 static_assert(GeckoProcessType_Utility + 1 == GeckoProcessType_End,
1333 "Did not find the final GeckoProcessType");
1334
1335 NS_IMETHODIMP
GetProcessType(uint32_t * aResult)1336 nsXULAppInfo::GetProcessType(uint32_t* aResult) {
1337 NS_ENSURE_ARG_POINTER(aResult);
1338 *aResult = XRE_GetProcessType();
1339 return NS_OK;
1340 }
1341
1342 NS_IMETHODIMP
GetProcessID(uint32_t * aResult)1343 nsXULAppInfo::GetProcessID(uint32_t* aResult) {
1344 #ifdef XP_WIN
1345 *aResult = GetCurrentProcessId();
1346 #else
1347 *aResult = getpid();
1348 #endif
1349 return NS_OK;
1350 }
1351
1352 NS_IMETHODIMP
GetUniqueProcessID(uint64_t * aResult)1353 nsXULAppInfo::GetUniqueProcessID(uint64_t* aResult) {
1354 if (XRE_IsContentProcess()) {
1355 ContentChild* cc = ContentChild::GetSingleton();
1356 *aResult = cc->GetID();
1357 } else {
1358 *aResult = 0;
1359 }
1360 return NS_OK;
1361 }
1362
1363 NS_IMETHODIMP
GetRemoteType(nsACString & aRemoteType)1364 nsXULAppInfo::GetRemoteType(nsACString& aRemoteType) {
1365 if (XRE_IsContentProcess()) {
1366 aRemoteType = ContentChild::GetSingleton()->GetRemoteType();
1367 } else {
1368 aRemoteType = NOT_REMOTE_TYPE;
1369 }
1370
1371 return NS_OK;
1372 }
1373
1374 static nsCString gLastAppVersion;
1375 static nsCString gLastAppBuildID;
1376
1377 NS_IMETHODIMP
GetLastAppVersion(nsACString & aResult)1378 nsXULAppInfo::GetLastAppVersion(nsACString& aResult) {
1379 if (XRE_IsContentProcess()) {
1380 return NS_ERROR_NOT_AVAILABLE;
1381 }
1382
1383 if (!gLastAppVersion.IsVoid() && gLastAppVersion.IsEmpty()) {
1384 NS_WARNING("Attempt to retrieve lastAppVersion before it has been set.");
1385 return NS_ERROR_NOT_AVAILABLE;
1386 }
1387
1388 aResult.Assign(gLastAppVersion);
1389 return NS_OK;
1390 }
1391
1392 NS_IMETHODIMP
GetLastAppBuildID(nsACString & aResult)1393 nsXULAppInfo::GetLastAppBuildID(nsACString& aResult) {
1394 if (XRE_IsContentProcess()) {
1395 return NS_ERROR_NOT_AVAILABLE;
1396 }
1397
1398 if (!gLastAppBuildID.IsVoid() && gLastAppBuildID.IsEmpty()) {
1399 NS_WARNING("Attempt to retrieve lastAppBuildID before it has been set.");
1400 return NS_ERROR_NOT_AVAILABLE;
1401 }
1402
1403 aResult.Assign(gLastAppBuildID);
1404 return NS_OK;
1405 }
1406
1407 NS_IMETHODIMP
GetFissionAutostart(bool * aResult)1408 nsXULAppInfo::GetFissionAutostart(bool* aResult) {
1409 *aResult = FissionAutostart();
1410 return NS_OK;
1411 }
1412
1413 NS_IMETHODIMP
GetWin32kExperimentStatus(ExperimentStatus * aResult)1414 nsXULAppInfo::GetWin32kExperimentStatus(ExperimentStatus* aResult) {
1415 if (!XRE_IsParentProcess()) {
1416 return NS_ERROR_NOT_AVAILABLE;
1417 }
1418
1419 EnsureWin32kInitialized();
1420 *aResult = gWin32kExperimentStatus;
1421 return NS_OK;
1422 }
1423
1424 NS_IMETHODIMP
GetWin32kLiveStatusTestingOnly(nsIXULRuntime::ContentWin32kLockdownState * aResult)1425 nsXULAppInfo::GetWin32kLiveStatusTestingOnly(
1426 nsIXULRuntime::ContentWin32kLockdownState* aResult) {
1427 if (!XRE_IsParentProcess()) {
1428 return NS_ERROR_NOT_AVAILABLE;
1429 }
1430
1431 EnsureWin32kInitialized();
1432 *aResult = GetLiveWin32kLockdownState();
1433 return NS_OK;
1434 }
1435
1436 NS_IMETHODIMP
GetWin32kSessionStatus(nsIXULRuntime::ContentWin32kLockdownState * aResult)1437 nsXULAppInfo::GetWin32kSessionStatus(
1438 nsIXULRuntime::ContentWin32kLockdownState* aResult) {
1439 if (!XRE_IsParentProcess()) {
1440 return NS_ERROR_NOT_AVAILABLE;
1441 }
1442
1443 EnsureWin32kInitialized();
1444 *aResult = gWin32kStatus;
1445 return NS_OK;
1446 }
1447
1448 NS_IMETHODIMP
GetFissionExperimentStatus(ExperimentStatus * aResult)1449 nsXULAppInfo::GetFissionExperimentStatus(ExperimentStatus* aResult) {
1450 if (!XRE_IsParentProcess()) {
1451 return NS_ERROR_NOT_AVAILABLE;
1452 }
1453
1454 EnsureFissionAutostartInitialized();
1455 *aResult = gFissionExperimentStatus;
1456 return NS_OK;
1457 }
1458
1459 NS_IMETHODIMP
GetFissionDecisionStatus(FissionDecisionStatus * aResult)1460 nsXULAppInfo::GetFissionDecisionStatus(FissionDecisionStatus* aResult) {
1461 if (!XRE_IsParentProcess()) {
1462 return NS_ERROR_NOT_AVAILABLE;
1463 }
1464
1465 EnsureFissionAutostartInitialized();
1466
1467 MOZ_ASSERT(gFissionDecisionStatus != eFissionStatusUnknown);
1468 *aResult = gFissionDecisionStatus;
1469 return NS_OK;
1470 }
1471
1472 NS_IMETHODIMP
GetFissionDecisionStatusString(nsACString & aResult)1473 nsXULAppInfo::GetFissionDecisionStatusString(nsACString& aResult) {
1474 if (!XRE_IsParentProcess()) {
1475 return NS_ERROR_NOT_AVAILABLE;
1476 }
1477
1478 EnsureFissionAutostartInitialized();
1479 switch (gFissionDecisionStatus) {
1480 case eFissionExperimentControl:
1481 aResult = "experimentControl";
1482 break;
1483 case eFissionExperimentTreatment:
1484 aResult = "experimentTreatment";
1485 break;
1486 case eFissionDisabledByE10sEnv:
1487 aResult = "disabledByE10sEnv";
1488 break;
1489 case eFissionEnabledByEnv:
1490 aResult = "enabledByEnv";
1491 break;
1492 case eFissionDisabledByEnv:
1493 aResult = "disabledByEnv";
1494 break;
1495 case eFissionDisabledBySafeMode:
1496 aResult = "disabledBySafeMode";
1497 break;
1498 case eFissionEnabledByDefault:
1499 aResult = "enabledByDefault";
1500 break;
1501 case eFissionDisabledByDefault:
1502 aResult = "disabledByDefault";
1503 break;
1504 case eFissionEnabledByUserPref:
1505 aResult = "enabledByUserPref";
1506 break;
1507 case eFissionDisabledByUserPref:
1508 aResult = "disabledByUserPref";
1509 break;
1510 case eFissionDisabledByE10sOther:
1511 aResult = "disabledByE10sOther";
1512 break;
1513 case eFissionEnabledByRollout:
1514 aResult = "enabledByRollout";
1515 break;
1516 default:
1517 MOZ_ASSERT_UNREACHABLE("Unexpected enum value");
1518 }
1519 return NS_OK;
1520 }
1521
1522 NS_IMETHODIMP
GetSessionHistoryInParent(bool * aResult)1523 nsXULAppInfo::GetSessionHistoryInParent(bool* aResult) {
1524 *aResult = SessionHistoryInParent();
1525 return NS_OK;
1526 }
1527
1528 NS_IMETHODIMP
GetBrowserTabsRemoteAutostart(bool * aResult)1529 nsXULAppInfo::GetBrowserTabsRemoteAutostart(bool* aResult) {
1530 *aResult = BrowserTabsRemoteAutostart();
1531 return NS_OK;
1532 }
1533
1534 NS_IMETHODIMP
GetMaxWebProcessCount(uint32_t * aResult)1535 nsXULAppInfo::GetMaxWebProcessCount(uint32_t* aResult) {
1536 *aResult = mozilla::GetMaxWebProcessCount();
1537 return NS_OK;
1538 }
1539
1540 NS_IMETHODIMP
GetAccessibilityEnabled(bool * aResult)1541 nsXULAppInfo::GetAccessibilityEnabled(bool* aResult) {
1542 #ifdef ACCESSIBILITY
1543 *aResult = GetAccService() != nullptr;
1544 #else
1545 *aResult = false;
1546 #endif
1547 return NS_OK;
1548 }
1549
1550 NS_IMETHODIMP
GetAccessibleHandlerUsed(bool * aResult)1551 nsXULAppInfo::GetAccessibleHandlerUsed(bool* aResult) {
1552 #if defined(ACCESSIBILITY) && defined(XP_WIN)
1553 *aResult = Preferences::GetBool("accessibility.handler.enabled", false) &&
1554 a11y::IsHandlerRegistered();
1555 #else
1556 *aResult = false;
1557 #endif
1558 return NS_OK;
1559 }
1560
1561 NS_IMETHODIMP
GetAccessibilityInstantiator(nsAString & aInstantiator)1562 nsXULAppInfo::GetAccessibilityInstantiator(nsAString& aInstantiator) {
1563 #if defined(ACCESSIBILITY) && defined(XP_WIN)
1564 if (!GetAccService()) {
1565 aInstantiator.Truncate();
1566 return NS_OK;
1567 }
1568 nsAutoString ipClientInfo;
1569 a11y::Compatibility::GetHumanReadableConsumersStr(ipClientInfo);
1570 aInstantiator.Append(ipClientInfo);
1571 aInstantiator.AppendLiteral("|");
1572
1573 nsCOMPtr<nsIFile> oopClientExe;
1574 if (a11y::GetInstantiator(getter_AddRefs(oopClientExe))) {
1575 nsAutoString oopClientInfo;
1576 if (NS_SUCCEEDED(oopClientExe->GetPath(oopClientInfo))) {
1577 aInstantiator.Append(oopClientInfo);
1578 }
1579 }
1580 #else
1581 aInstantiator.Truncate();
1582 #endif
1583 return NS_OK;
1584 }
1585
1586 NS_IMETHODIMP
GetShouldBlockIncompatJaws(bool * aResult)1587 nsXULAppInfo::GetShouldBlockIncompatJaws(bool* aResult) {
1588 *aResult = false;
1589 #if defined(ACCESSIBILITY) && defined(XP_WIN)
1590 *aResult = mozilla::a11y::Compatibility::IsOldJAWS();
1591 #endif
1592 return NS_OK;
1593 }
1594
1595 NS_IMETHODIMP
GetIs64Bit(bool * aResult)1596 nsXULAppInfo::GetIs64Bit(bool* aResult) {
1597 #ifdef HAVE_64BIT_BUILD
1598 *aResult = true;
1599 #else
1600 *aResult = false;
1601 #endif
1602 return NS_OK;
1603 }
1604
1605 NS_IMETHODIMP
EnsureContentProcess()1606 nsXULAppInfo::EnsureContentProcess() {
1607 if (!XRE_IsParentProcess()) return NS_ERROR_NOT_AVAILABLE;
1608
1609 RefPtr<ContentParent> unused =
1610 ContentParent::GetNewOrUsedBrowserProcess(DEFAULT_REMOTE_TYPE);
1611 return NS_OK;
1612 }
1613
1614 NS_IMETHODIMP
InvalidateCachesOnRestart()1615 nsXULAppInfo::InvalidateCachesOnRestart() {
1616 nsCOMPtr<nsIFile> file;
1617 nsresult rv =
1618 NS_GetSpecialDirectory(NS_APP_PROFILE_DIR_STARTUP, getter_AddRefs(file));
1619 if (NS_FAILED(rv)) return rv;
1620 if (!file) return NS_ERROR_NOT_AVAILABLE;
1621
1622 file->AppendNative(FILE_COMPATIBILITY_INFO);
1623
1624 nsINIParser parser;
1625 rv = parser.Init(file);
1626 if (NS_FAILED(rv)) {
1627 // This fails if compatibility.ini is not there, so we'll
1628 // flush the caches on the next restart anyways.
1629 return NS_OK;
1630 }
1631
1632 nsAutoCString buf;
1633 rv = parser.GetString("Compatibility", "InvalidateCaches", buf);
1634
1635 if (NS_FAILED(rv)) {
1636 PRFileDesc* fd;
1637 rv = file->OpenNSPRFileDesc(PR_RDWR | PR_APPEND, 0600, &fd);
1638 if (NS_FAILED(rv)) {
1639 NS_ERROR("could not create output stream");
1640 return NS_ERROR_NOT_AVAILABLE;
1641 }
1642 static const char kInvalidationHeader[] =
1643 NS_LINEBREAK "InvalidateCaches=1" NS_LINEBREAK;
1644 PR_Write(fd, kInvalidationHeader, sizeof(kInvalidationHeader) - 1);
1645 PR_Close(fd);
1646 }
1647 return NS_OK;
1648 }
1649
1650 NS_IMETHODIMP
GetReplacedLockTime(PRTime * aReplacedLockTime)1651 nsXULAppInfo::GetReplacedLockTime(PRTime* aReplacedLockTime) {
1652 if (!gProfileLock) return NS_ERROR_NOT_AVAILABLE;
1653 gProfileLock->GetReplacedLockTime(aReplacedLockTime);
1654 return NS_OK;
1655 }
1656
1657 NS_IMETHODIMP
GetDefaultUpdateChannel(nsACString & aResult)1658 nsXULAppInfo::GetDefaultUpdateChannel(nsACString& aResult) {
1659 aResult.AssignLiteral(MOZ_STRINGIFY(MOZ_UPDATE_CHANNEL));
1660 return NS_OK;
1661 }
1662
1663 NS_IMETHODIMP
GetDistributionID(nsACString & aResult)1664 nsXULAppInfo::GetDistributionID(nsACString& aResult) {
1665 aResult.AssignLiteral(MOZ_DISTRIBUTION_ID);
1666 return NS_OK;
1667 }
1668
1669 NS_IMETHODIMP
GetWindowsDLLBlocklistStatus(bool * aResult)1670 nsXULAppInfo::GetWindowsDLLBlocklistStatus(bool* aResult) {
1671 #if defined(HAS_DLL_BLOCKLIST)
1672 *aResult = DllBlocklist_CheckStatus();
1673 #else
1674 *aResult = false;
1675 #endif
1676 return NS_OK;
1677 }
1678
1679 NS_IMETHODIMP
GetRestartedByOS(bool * aResult)1680 nsXULAppInfo::GetRestartedByOS(bool* aResult) {
1681 *aResult = gRestartedByOS;
1682 return NS_OK;
1683 }
1684
1685 NS_IMETHODIMP
GetChromeColorSchemeIsDark(bool * aResult)1686 nsXULAppInfo::GetChromeColorSchemeIsDark(bool* aResult) {
1687 LookAndFeel::EnsureColorSchemesInitialized();
1688 *aResult = LookAndFeel::ColorSchemeForChrome() == ColorScheme::Dark;
1689 return NS_OK;
1690 }
1691
1692 NS_IMETHODIMP
GetContentThemeDerivedColorSchemeIsDark(bool * aResult)1693 nsXULAppInfo::GetContentThemeDerivedColorSchemeIsDark(bool* aResult) {
1694 *aResult =
1695 LookAndFeel::ThemeDerivedColorSchemeForContent() == ColorScheme::Dark;
1696 return NS_OK;
1697 }
1698
1699 NS_IMETHODIMP
GetDrawInTitlebar(bool * aResult)1700 nsXULAppInfo::GetDrawInTitlebar(bool* aResult) {
1701 *aResult = LookAndFeel::DrawInTitlebar();
1702 return NS_OK;
1703 }
1704
1705 NS_IMETHODIMP
GetProcessStartupShortcut(nsAString & aShortcut)1706 nsXULAppInfo::GetProcessStartupShortcut(nsAString& aShortcut) {
1707 #if defined(XP_WIN)
1708 if (XRE_IsParentProcess()) {
1709 aShortcut.Assign(gProcessStartupShortcut);
1710 return NS_OK;
1711 }
1712 #endif
1713 return NS_ERROR_NOT_AVAILABLE;
1714 }
1715
1716 #if defined(XP_WIN) && defined(MOZ_LAUNCHER_PROCESS)
1717 // Forward declaration
1718 void SetupLauncherProcessPref();
1719
1720 static Maybe<LauncherRegistryInfo::EnabledState> gLauncherProcessState;
1721 #endif // defined(XP_WIN) && defined(MOZ_LAUNCHER_PROCESS)
1722
1723 NS_IMETHODIMP
GetLauncherProcessState(uint32_t * aResult)1724 nsXULAppInfo::GetLauncherProcessState(uint32_t* aResult) {
1725 #if defined(XP_WIN) && defined(MOZ_LAUNCHER_PROCESS)
1726 SetupLauncherProcessPref();
1727
1728 if (!gLauncherProcessState) {
1729 return NS_ERROR_UNEXPECTED;
1730 }
1731
1732 *aResult = static_cast<uint32_t>(gLauncherProcessState.value());
1733 return NS_OK;
1734 #else
1735 return NS_ERROR_NOT_AVAILABLE;
1736 #endif
1737 }
1738
1739 #ifdef XP_WIN
1740 NS_IMETHODIMP
GetUserCanElevate(bool * aUserCanElevate)1741 nsXULAppInfo::GetUserCanElevate(bool* aUserCanElevate) {
1742 HANDLE rawToken;
1743 if (!::OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY, &rawToken)) {
1744 *aUserCanElevate = false;
1745 return NS_OK;
1746 }
1747
1748 nsAutoHandle token(rawToken);
1749 LauncherResult<TOKEN_ELEVATION_TYPE> elevationType = GetElevationType(token);
1750 if (elevationType.isErr()) {
1751 *aUserCanElevate = false;
1752 return NS_OK;
1753 }
1754
1755 // The possible values returned for elevationType and their meanings are:
1756 // TokenElevationTypeDefault: The token does not have a linked token
1757 // (e.g. UAC disabled or a standard user, so they can't be elevated)
1758 // TokenElevationTypeFull: The token is linked to an elevated token
1759 // (e.g. UAC is enabled and the user is already elevated so they can't
1760 // be elevated again)
1761 // TokenElevationTypeLimited: The token is linked to a limited token
1762 // (e.g. UAC is enabled and the user is not elevated, so they can be
1763 // elevated)
1764 *aUserCanElevate = (elevationType.inspect() == TokenElevationTypeLimited);
1765 return NS_OK;
1766 }
1767 #endif
1768
1769 NS_IMETHODIMP
GetEnabled(bool * aEnabled)1770 nsXULAppInfo::GetEnabled(bool* aEnabled) {
1771 *aEnabled = CrashReporter::GetEnabled();
1772 return NS_OK;
1773 }
1774
1775 NS_IMETHODIMP
SetEnabled(bool aEnabled)1776 nsXULAppInfo::SetEnabled(bool aEnabled) {
1777 if (aEnabled) {
1778 if (CrashReporter::GetEnabled()) {
1779 // no point in erroring for double-enabling
1780 return NS_OK;
1781 }
1782
1783 nsCOMPtr<nsIFile> greBinDir;
1784 NS_GetSpecialDirectory(NS_GRE_BIN_DIR, getter_AddRefs(greBinDir));
1785 if (!greBinDir) {
1786 return NS_ERROR_FAILURE;
1787 }
1788
1789 nsCOMPtr<nsIFile> xreBinDirectory = greBinDir;
1790 if (!xreBinDirectory) {
1791 return NS_ERROR_FAILURE;
1792 }
1793
1794 return CrashReporter::SetExceptionHandler(xreBinDirectory, true);
1795 }
1796
1797 if (!CrashReporter::GetEnabled()) {
1798 // no point in erroring for double-disabling
1799 return NS_OK;
1800 }
1801
1802 return CrashReporter::UnsetExceptionHandler();
1803 }
1804
1805 NS_IMETHODIMP
GetServerURL(nsIURL ** aServerURL)1806 nsXULAppInfo::GetServerURL(nsIURL** aServerURL) {
1807 NS_ENSURE_ARG_POINTER(aServerURL);
1808 if (!CrashReporter::GetEnabled()) return NS_ERROR_NOT_INITIALIZED;
1809
1810 nsAutoCString data;
1811 if (!CrashReporter::GetServerURL(data)) {
1812 return NS_ERROR_FAILURE;
1813 }
1814 nsCOMPtr<nsIURI> uri;
1815 NS_NewURI(getter_AddRefs(uri), data);
1816 if (!uri) return NS_ERROR_FAILURE;
1817
1818 nsCOMPtr<nsIURL> url;
1819 url = do_QueryInterface(uri);
1820 NS_ADDREF(*aServerURL = url);
1821
1822 return NS_OK;
1823 }
1824
1825 NS_IMETHODIMP
SetServerURL(nsIURL * aServerURL)1826 nsXULAppInfo::SetServerURL(nsIURL* aServerURL) {
1827 // Only allow https or http URLs
1828 if (!aServerURL->SchemeIs("http") && !aServerURL->SchemeIs("https")) {
1829 return NS_ERROR_INVALID_ARG;
1830 }
1831
1832 nsAutoCString spec;
1833 nsresult rv = aServerURL->GetSpec(spec);
1834 NS_ENSURE_SUCCESS(rv, rv);
1835
1836 return CrashReporter::SetServerURL(spec);
1837 }
1838
1839 NS_IMETHODIMP
GetMinidumpPath(nsIFile ** aMinidumpPath)1840 nsXULAppInfo::GetMinidumpPath(nsIFile** aMinidumpPath) {
1841 if (!CrashReporter::GetEnabled()) return NS_ERROR_NOT_INITIALIZED;
1842
1843 nsAutoString path;
1844 if (!CrashReporter::GetMinidumpPath(path)) return NS_ERROR_FAILURE;
1845
1846 nsresult rv = NS_NewLocalFile(path, false, aMinidumpPath);
1847 NS_ENSURE_SUCCESS(rv, rv);
1848 return NS_OK;
1849 }
1850
1851 NS_IMETHODIMP
SetMinidumpPath(nsIFile * aMinidumpPath)1852 nsXULAppInfo::SetMinidumpPath(nsIFile* aMinidumpPath) {
1853 nsAutoString path;
1854 nsresult rv = aMinidumpPath->GetPath(path);
1855 NS_ENSURE_SUCCESS(rv, rv);
1856 return CrashReporter::SetMinidumpPath(path);
1857 }
1858
1859 NS_IMETHODIMP
GetMinidumpForID(const nsAString & aId,nsIFile ** aMinidump)1860 nsXULAppInfo::GetMinidumpForID(const nsAString& aId, nsIFile** aMinidump) {
1861 if (!CrashReporter::GetMinidumpForID(aId, aMinidump)) {
1862 return NS_ERROR_FILE_NOT_FOUND;
1863 }
1864
1865 return NS_OK;
1866 }
1867
1868 NS_IMETHODIMP
GetExtraFileForID(const nsAString & aId,nsIFile ** aExtraFile)1869 nsXULAppInfo::GetExtraFileForID(const nsAString& aId, nsIFile** aExtraFile) {
1870 if (!CrashReporter::GetExtraFileForID(aId, aExtraFile)) {
1871 return NS_ERROR_FILE_NOT_FOUND;
1872 }
1873
1874 return NS_OK;
1875 }
1876
1877 NS_IMETHODIMP
AnnotateCrashReport(const nsACString & key,const nsACString & data)1878 nsXULAppInfo::AnnotateCrashReport(const nsACString& key,
1879 const nsACString& data) {
1880 CrashReporter::Annotation annotation;
1881
1882 if (!AnnotationFromString(annotation, PromiseFlatCString(key).get())) {
1883 return NS_ERROR_INVALID_ARG;
1884 }
1885
1886 return CrashReporter::AnnotateCrashReport(annotation, data);
1887 }
1888
1889 NS_IMETHODIMP
RemoveCrashReportAnnotation(const nsACString & key)1890 nsXULAppInfo::RemoveCrashReportAnnotation(const nsACString& key) {
1891 CrashReporter::Annotation annotation;
1892
1893 if (!AnnotationFromString(annotation, PromiseFlatCString(key).get())) {
1894 return NS_ERROR_INVALID_ARG;
1895 }
1896
1897 return CrashReporter::RemoveCrashReportAnnotation(annotation);
1898 }
1899
1900 NS_IMETHODIMP
IsAnnotationWhitelistedForPing(const nsACString & aValue,bool * aIsWhitelisted)1901 nsXULAppInfo::IsAnnotationWhitelistedForPing(const nsACString& aValue,
1902 bool* aIsWhitelisted) {
1903 CrashReporter::Annotation annotation;
1904
1905 if (!AnnotationFromString(annotation, PromiseFlatCString(aValue).get())) {
1906 return NS_ERROR_INVALID_ARG;
1907 }
1908
1909 *aIsWhitelisted = CrashReporter::IsAnnotationWhitelistedForPing(annotation);
1910
1911 return NS_OK;
1912 }
1913
1914 NS_IMETHODIMP
AppendAppNotesToCrashReport(const nsACString & data)1915 nsXULAppInfo::AppendAppNotesToCrashReport(const nsACString& data) {
1916 return CrashReporter::AppendAppNotesToCrashReport(data);
1917 }
1918
1919 NS_IMETHODIMP
RegisterAppMemory(uint64_t pointer,uint64_t len)1920 nsXULAppInfo::RegisterAppMemory(uint64_t pointer, uint64_t len) {
1921 return CrashReporter::RegisterAppMemory((void*)pointer, len);
1922 }
1923
1924 NS_IMETHODIMP
WriteMinidumpForException(void * aExceptionInfo)1925 nsXULAppInfo::WriteMinidumpForException(void* aExceptionInfo) {
1926 #ifdef XP_WIN
1927 return CrashReporter::WriteMinidumpForException(
1928 static_cast<EXCEPTION_POINTERS*>(aExceptionInfo));
1929 #else
1930 return NS_ERROR_NOT_IMPLEMENTED;
1931 #endif
1932 }
1933
1934 NS_IMETHODIMP
AppendObjCExceptionInfoToAppNotes(void * aException)1935 nsXULAppInfo::AppendObjCExceptionInfoToAppNotes(void* aException) {
1936 #ifdef XP_MACOSX
1937 return CrashReporter::AppendObjCExceptionInfoToAppNotes(aException);
1938 #else
1939 return NS_ERROR_NOT_IMPLEMENTED;
1940 #endif
1941 }
1942
1943 NS_IMETHODIMP
GetSubmitReports(bool * aEnabled)1944 nsXULAppInfo::GetSubmitReports(bool* aEnabled) {
1945 return CrashReporter::GetSubmitReports(aEnabled);
1946 }
1947
1948 NS_IMETHODIMP
SetSubmitReports(bool aEnabled)1949 nsXULAppInfo::SetSubmitReports(bool aEnabled) {
1950 return CrashReporter::SetSubmitReports(aEnabled);
1951 }
1952
1953 NS_IMETHODIMP
UpdateCrashEventsDir()1954 nsXULAppInfo::UpdateCrashEventsDir() {
1955 CrashReporter::UpdateCrashEventsDir();
1956 return NS_OK;
1957 }
1958
1959 NS_IMETHODIMP
SaveMemoryReport()1960 nsXULAppInfo::SaveMemoryReport() {
1961 if (!CrashReporter::GetEnabled()) {
1962 return NS_ERROR_NOT_INITIALIZED;
1963 }
1964 nsCOMPtr<nsIFile> file;
1965 nsresult rv = CrashReporter::GetDefaultMemoryReportFile(getter_AddRefs(file));
1966 if (NS_WARN_IF(NS_FAILED(rv))) {
1967 return rv;
1968 }
1969
1970 nsString path;
1971 file->GetPath(path);
1972
1973 nsCOMPtr<nsIMemoryInfoDumper> dumper =
1974 do_GetService("@mozilla.org/memory-info-dumper;1");
1975 if (NS_WARN_IF(!dumper)) {
1976 return NS_ERROR_UNEXPECTED;
1977 }
1978
1979 rv = dumper->DumpMemoryReportsToNamedFile(
1980 path, this, file, true /* anonymize */, false /* minimizeMemoryUsage */);
1981 if (NS_WARN_IF(NS_FAILED(rv))) {
1982 return rv;
1983 }
1984 return NS_OK;
1985 }
1986
1987 // This method is from nsIFInishDumpingCallback.
1988 NS_IMETHODIMP
Callback(nsISupports * aData)1989 nsXULAppInfo::Callback(nsISupports* aData) {
1990 nsCOMPtr<nsIFile> file = do_QueryInterface(aData);
1991 MOZ_ASSERT(file);
1992
1993 CrashReporter::SetMemoryReportFile(file);
1994 return NS_OK;
1995 }
1996
1997 static const nsXULAppInfo kAppInfo;
1998 namespace mozilla {
AppInfoConstructor(nsISupports * aOuter,REFNSIID aIID,void ** aResult)1999 nsresult AppInfoConstructor(nsISupports* aOuter, REFNSIID aIID,
2000 void** aResult) {
2001 NS_ENSURE_NO_AGGREGATION(aOuter);
2002
2003 return const_cast<nsXULAppInfo*>(&kAppInfo)->QueryInterface(aIID, aResult);
2004 }
2005 } // namespace mozilla
2006
2007 bool gLogConsoleErrors = false;
2008
2009 #define NS_ENSURE_TRUE_LOG(x, ret) \
2010 PR_BEGIN_MACRO \
2011 if (MOZ_UNLIKELY(!(x))) { \
2012 NS_WARNING("NS_ENSURE_TRUE(" #x ") failed"); \
2013 gLogConsoleErrors = true; \
2014 return ret; \
2015 } \
2016 PR_END_MACRO
2017
2018 #define NS_ENSURE_SUCCESS_LOG(res, ret) \
2019 NS_ENSURE_TRUE_LOG(NS_SUCCEEDED(res), ret)
2020
2021 /**
2022 * Because we're starting/stopping XPCOM several times in different scenarios,
2023 * this class is a stack-based critter that makes sure that XPCOM is shut down
2024 * during early returns.
2025 */
2026
2027 class ScopedXPCOMStartup {
2028 public:
ScopedXPCOMStartup()2029 ScopedXPCOMStartup() : mServiceManager(nullptr) {}
2030 ~ScopedXPCOMStartup();
2031
2032 nsresult Initialize(bool aInitJSContext = true);
2033 nsresult SetWindowCreator(nsINativeAppSupport* native);
2034
2035 private:
2036 nsIServiceManager* mServiceManager;
2037 static nsINativeAppSupport* gNativeAppSupport;
2038
2039 friend already_AddRefed<nsINativeAppSupport> NS_GetNativeAppSupport();
2040 };
2041
~ScopedXPCOMStartup()2042 ScopedXPCOMStartup::~ScopedXPCOMStartup() {
2043 NS_IF_RELEASE(gNativeAppSupport);
2044
2045 if (mServiceManager) {
2046 #ifdef XP_MACOSX
2047 // On OS X, we need a pool to catch cocoa objects that are autoreleased
2048 // during teardown.
2049 mozilla::MacAutoreleasePool pool;
2050 #endif
2051
2052 nsCOMPtr<nsIAppStartup> appStartup(components::AppStartup::Service());
2053 if (appStartup) appStartup->DestroyHiddenWindow();
2054
2055 gDirServiceProvider->DoShutdown();
2056 PROFILER_MARKER_UNTYPED("Shutdown early", OTHER);
2057
2058 WriteConsoleLog();
2059
2060 NS_ShutdownXPCOM(mServiceManager);
2061 mServiceManager = nullptr;
2062 }
2063 }
2064
2065 // {5F5E59CE-27BC-47eb-9D1F-B09CA9049836}
2066 static const nsCID kProfileServiceCID = {
2067 0x5f5e59ce,
2068 0x27bc,
2069 0x47eb,
2070 {0x9d, 0x1f, 0xb0, 0x9c, 0xa9, 0x4, 0x98, 0x36}};
2071
ProfileServiceFactoryConstructor(const mozilla::Module & module,const mozilla::Module::CIDEntry & entry)2072 static already_AddRefed<nsIFactory> ProfileServiceFactoryConstructor(
2073 const mozilla::Module& module, const mozilla::Module::CIDEntry& entry) {
2074 nsCOMPtr<nsIFactory> factory;
2075 NS_NewToolkitProfileFactory(getter_AddRefs(factory));
2076 return factory.forget();
2077 }
2078
2079 static const mozilla::Module::CIDEntry kXRECIDs[] = {
2080 {&kProfileServiceCID, false, ProfileServiceFactoryConstructor, nullptr},
2081 {nullptr}};
2082
2083 static const mozilla::Module::ContractIDEntry kXREContracts[] = {
2084 {NS_PROFILESERVICE_CONTRACTID, &kProfileServiceCID}, {nullptr}};
2085
2086 extern const mozilla::Module kXREModule = {mozilla::Module::kVersion, kXRECIDs,
2087 kXREContracts};
2088
Initialize(bool aInitJSContext)2089 nsresult ScopedXPCOMStartup::Initialize(bool aInitJSContext) {
2090 NS_ASSERTION(gDirServiceProvider, "Should not get here!");
2091
2092 nsresult rv;
2093
2094 rv = NS_InitXPCOM(&mServiceManager, gDirServiceProvider->GetAppDir(),
2095 gDirServiceProvider, aInitJSContext);
2096 if (NS_FAILED(rv)) {
2097 NS_ERROR("Couldn't start xpcom!");
2098 mServiceManager = nullptr;
2099 } else {
2100 #ifdef DEBUG
2101 nsCOMPtr<nsIComponentRegistrar> reg = do_QueryInterface(mServiceManager);
2102 NS_ASSERTION(reg, "Service Manager doesn't QI to Registrar.");
2103 #endif
2104 }
2105
2106 return rv;
2107 }
2108
2109 /**
2110 * This is a little factory class that serves as a singleton-service-factory
2111 * for the nativeappsupport object.
2112 */
2113 class nsSingletonFactory final : public nsIFactory {
2114 public:
2115 NS_DECL_ISUPPORTS
2116 NS_DECL_NSIFACTORY
2117
2118 explicit nsSingletonFactory(nsISupports* aSingleton);
2119
2120 private:
2121 ~nsSingletonFactory() = default;
2122 nsCOMPtr<nsISupports> mSingleton;
2123 };
2124
nsSingletonFactory(nsISupports * aSingleton)2125 nsSingletonFactory::nsSingletonFactory(nsISupports* aSingleton)
2126 : mSingleton(aSingleton) {
2127 NS_ASSERTION(mSingleton, "Singleton was null!");
2128 }
2129
NS_IMPL_ISUPPORTS(nsSingletonFactory,nsIFactory)2130 NS_IMPL_ISUPPORTS(nsSingletonFactory, nsIFactory)
2131
2132 NS_IMETHODIMP
2133 nsSingletonFactory::CreateInstance(nsISupports* aOuter, const nsIID& aIID,
2134 void** aResult) {
2135 NS_ENSURE_NO_AGGREGATION(aOuter);
2136
2137 return mSingleton->QueryInterface(aIID, aResult);
2138 }
2139
2140 NS_IMETHODIMP
LockFactory(bool)2141 nsSingletonFactory::LockFactory(bool) { return NS_OK; }
2142
2143 /**
2144 * Set our windowcreator on the WindowWatcher service.
2145 */
SetWindowCreator(nsINativeAppSupport * native)2146 nsresult ScopedXPCOMStartup::SetWindowCreator(nsINativeAppSupport* native) {
2147 nsresult rv;
2148
2149 NS_IF_ADDREF(gNativeAppSupport = native);
2150
2151 nsCOMPtr<nsIWindowCreator> creator(components::AppStartup::Service());
2152 if (!creator) return NS_ERROR_UNEXPECTED;
2153
2154 nsCOMPtr<nsIWindowWatcher> wwatch(
2155 do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv));
2156 NS_ENSURE_SUCCESS(rv, rv);
2157
2158 return wwatch->SetWindowCreator(creator);
2159 }
2160
NS_GetNativeAppSupport()2161 /* static */ already_AddRefed<nsINativeAppSupport> NS_GetNativeAppSupport() {
2162 if (!ScopedXPCOMStartup::gNativeAppSupport) {
2163 return nullptr;
2164 }
2165
2166 return do_AddRef(ScopedXPCOMStartup::gNativeAppSupport);
2167 }
2168
2169 nsINativeAppSupport* ScopedXPCOMStartup::gNativeAppSupport;
2170
DumpArbitraryHelp()2171 static void DumpArbitraryHelp() {
2172 nsresult rv;
2173
2174 ScopedLogging log;
2175
2176 {
2177 ScopedXPCOMStartup xpcom;
2178 xpcom.Initialize();
2179
2180 nsCOMPtr<nsICommandLineRunner> cmdline(new nsCommandLine());
2181
2182 nsCString text;
2183 rv = cmdline->GetHelpText(text);
2184 if (NS_SUCCEEDED(rv)) printf("%s", text.get());
2185 }
2186 }
2187
2188 // English text needs to go into a dtd file.
2189 // But when this is called we have no components etc. These strings must either
2190 // be here, or in a native resource file.
DumpHelp()2191 static void DumpHelp() {
2192 printf(
2193 "Usage: %s [ options ... ] [URL]\n"
2194 " where options include:\n\n",
2195 gArgv[0]);
2196
2197 #ifdef MOZ_X11
2198 printf(
2199 "X11 options\n"
2200 " --display=DISPLAY X display to use\n"
2201 " --sync Make X calls synchronous\n");
2202 #endif
2203 #ifdef XP_UNIX
2204 printf(
2205 " --g-fatal-warnings Make all warnings fatal\n"
2206 "\n%s options\n",
2207 (const char*)gAppData->name);
2208 #endif
2209
2210 printf(
2211 " -h or --help Print this message.\n"
2212 " -v or --version Print %s version.\n"
2213 " --full-version Print %s version, build and platform build ids.\n"
2214 " -P <profile> Start with <profile>.\n"
2215 " --profile <path> Start with profile at <path>.\n"
2216 " --migration Start with migration wizard.\n"
2217 " --ProfileManager Start with ProfileManager.\n"
2218 #ifdef MOZ_HAS_REMOTE
2219 " --no-remote Do not accept or send remote commands; implies\n"
2220 " --new-instance.\n"
2221 " --new-instance Open new instance, not a new window in running "
2222 "instance.\n"
2223 #endif
2224 " --safe-mode Disables extensions and themes for this session.\n"
2225 #ifdef MOZ_BLOCK_PROFILE_DOWNGRADE
2226 " --allow-downgrade Allows downgrading a profile.\n"
2227 #endif
2228 " --MOZ_LOG=<modules> Treated as MOZ_LOG=<modules> environment "
2229 "variable,\n"
2230 " overrides it.\n"
2231 " --MOZ_LOG_FILE=<file> Treated as MOZ_LOG_FILE=<file> environment "
2232 "variable,\n"
2233 " overrides it. If MOZ_LOG_FILE is not specified as "
2234 "an\n"
2235 " argument or as an environment variable, logging "
2236 "will be\n"
2237 " written to stdout.\n",
2238 (const char*)gAppData->name, (const char*)gAppData->name);
2239
2240 #if defined(XP_WIN)
2241 printf(" --console Start %s with a debugging console.\n",
2242 (const char*)gAppData->name);
2243 #endif
2244
2245 #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) || defined(XP_MACOSX)
2246 printf(" --headless Run without a GUI.\n");
2247 #endif
2248
2249 // this works, but only after the components have registered. so if you drop
2250 // in a new command line handler, --help won't not until the second run. out
2251 // of the bug, because we ship a component.reg file, it works correctly.
2252 DumpArbitraryHelp();
2253 }
2254
DumpVersion()2255 static inline void DumpVersion() {
2256 if (gAppData->vendor) {
2257 printf("%s ", (const char*)gAppData->vendor);
2258 }
2259 printf("%s ", (const char*)gAppData->name);
2260
2261 // Use the displayed version
2262 // For example, for beta, we would display 42.0b2 instead of 42.0
2263 printf("%s", MOZ_STRINGIFY(MOZ_APP_VERSION_DISPLAY));
2264
2265 if (gAppData->copyright) {
2266 printf(", %s", (const char*)gAppData->copyright);
2267 }
2268 printf("\n");
2269 }
2270
DumpFullVersion()2271 static inline void DumpFullVersion() {
2272 if (gAppData->vendor) {
2273 printf("%s ", (const char*)gAppData->vendor);
2274 }
2275 printf("%s ", (const char*)gAppData->name);
2276
2277 // Use the displayed version
2278 // For example, for beta, we would display 42.0b2 instead of 42.0
2279 printf("%s ", MOZ_STRINGIFY(MOZ_APP_VERSION_DISPLAY));
2280
2281 printf("%s ", (const char*)gAppData->buildID);
2282 printf("%s ", (const char*)PlatformBuildID());
2283 if (gAppData->copyright) {
2284 printf(", %s", (const char*)gAppData->copyright);
2285 }
2286 printf("\n");
2287 }
2288
XRE_InitOmnijar(nsIFile * greOmni,nsIFile * appOmni)2289 void XRE_InitOmnijar(nsIFile* greOmni, nsIFile* appOmni) {
2290 mozilla::Omnijar::Init(greOmni, appOmni);
2291 }
2292
XRE_GetBinaryPath(nsIFile ** aResult)2293 nsresult XRE_GetBinaryPath(nsIFile** aResult) {
2294 return mozilla::BinaryPath::GetFile(aResult);
2295 }
2296
2297 #ifdef XP_WIN
2298 # include "nsWindowsRestart.cpp"
2299 # include <shellapi.h>
2300
2301 typedef BOOL(WINAPI* SetProcessDEPPolicyFunc)(DWORD dwFlags);
2302
RegisterApplicationRestartChanged(const char * aPref,void * aData)2303 static void RegisterApplicationRestartChanged(const char* aPref, void* aData) {
2304 DWORD cchCmdLine = 0;
2305 HRESULT rc = ::GetApplicationRestartSettings(::GetCurrentProcess(), nullptr,
2306 &cchCmdLine, nullptr);
2307 bool wasRegistered = false;
2308 if (rc == S_OK) {
2309 wasRegistered = true;
2310 }
2311
2312 if (Preferences::GetBool(PREF_WIN_REGISTER_APPLICATION_RESTART, false) &&
2313 !wasRegistered) {
2314 // Make the command line to use when restarting.
2315 // Excludes argv[0] because RegisterApplicationRestart adds the
2316 // executable name, replace that temporarily with -os-restarted
2317 char* exeName = gRestartArgv[0];
2318 gRestartArgv[0] = const_cast<char*>("-os-restarted");
2319 wchar_t** restartArgvConverted =
2320 AllocConvertUTF8toUTF16Strings(gRestartArgc, gRestartArgv);
2321 gRestartArgv[0] = exeName;
2322
2323 mozilla::UniquePtr<wchar_t[]> restartCommandLine;
2324 if (restartArgvConverted) {
2325 restartCommandLine =
2326 mozilla::MakeCommandLine(gRestartArgc, restartArgvConverted);
2327 FreeAllocStrings(gRestartArgc, restartArgvConverted);
2328 }
2329
2330 if (restartCommandLine) {
2331 // Flags RESTART_NO_PATCH and RESTART_NO_REBOOT are not set, so we
2332 // should be restarted if terminated by an update or restart.
2333 ::RegisterApplicationRestart(restartCommandLine.get(),
2334 RESTART_NO_CRASH | RESTART_NO_HANG);
2335 }
2336 } else if (wasRegistered) {
2337 ::UnregisterApplicationRestart();
2338 }
2339 }
2340
OnAlteredPrefetchPrefChanged(const char * aPref,void * aData)2341 static void OnAlteredPrefetchPrefChanged(const char* aPref, void* aData) {
2342 int32_t prefVal = Preferences::GetInt(PREF_WIN_ALTERED_DLL_PREFETCH, 0);
2343
2344 mozilla::DllPrefetchExperimentRegistryInfo prefetchRegInfo;
2345 mozilla::DebugOnly<mozilla::Result<Ok, nsresult>> reflectResult =
2346 prefetchRegInfo.ReflectPrefToRegistry(prefVal);
2347
2348 MOZ_ASSERT(reflectResult.value.isOk());
2349 }
2350
SetupAlteredPrefetchPref()2351 static void SetupAlteredPrefetchPref() {
2352 mozilla::DllPrefetchExperimentRegistryInfo prefetchRegInfo;
2353
2354 mozilla::DebugOnly<mozilla::Result<Ok, nsresult>> reflectResult =
2355 prefetchRegInfo.ReflectPrefToRegistry(
2356 Preferences::GetInt(PREF_WIN_ALTERED_DLL_PREFETCH, 0));
2357 MOZ_ASSERT(reflectResult.value.isOk());
2358
2359 Preferences::RegisterCallback(&OnAlteredPrefetchPrefChanged,
2360 PREF_WIN_ALTERED_DLL_PREFETCH);
2361 }
2362
ReflectSkeletonUIPrefToRegistry(const char * aPref,void * aData)2363 static void ReflectSkeletonUIPrefToRegistry(const char* aPref, void* aData) {
2364 Unused << aPref;
2365 Unused << aData;
2366
2367 bool shouldBeEnabled =
2368 Preferences::GetBool(kPrefPreXulSkeletonUI, false) &&
2369 Preferences::GetBool(kPrefBrowserStartupBlankWindow, false) &&
2370 LookAndFeel::DrawInTitlebar();
2371 if (shouldBeEnabled && Preferences::HasUserValue(kPrefThemeId)) {
2372 nsCString themeId;
2373 Preferences::GetCString(kPrefThemeId, themeId);
2374 if (themeId.EqualsLiteral("default-theme@mozilla.org")) {
2375 Unused << SetPreXULSkeletonUIThemeId(ThemeMode::Default);
2376 } else if (themeId.EqualsLiteral("firefox-compact-dark@mozilla.org")) {
2377 Unused << SetPreXULSkeletonUIThemeId(ThemeMode::Dark);
2378 } else if (themeId.EqualsLiteral("firefox-compact-light@mozilla.org")) {
2379 Unused << SetPreXULSkeletonUIThemeId(ThemeMode::Light);
2380 } else {
2381 shouldBeEnabled = false;
2382 }
2383 } else if (shouldBeEnabled) {
2384 Unused << SetPreXULSkeletonUIThemeId(ThemeMode::Default);
2385 }
2386
2387 if (GetPreXULSkeletonUIEnabled() != shouldBeEnabled) {
2388 Unused << SetPreXULSkeletonUIEnabledIfAllowed(shouldBeEnabled);
2389 }
2390 }
2391
SetupSkeletonUIPrefs()2392 static void SetupSkeletonUIPrefs() {
2393 ReflectSkeletonUIPrefToRegistry(nullptr, nullptr);
2394 Preferences::RegisterCallback(&ReflectSkeletonUIPrefToRegistry,
2395 kPrefPreXulSkeletonUI);
2396 Preferences::RegisterCallback(&ReflectSkeletonUIPrefToRegistry,
2397 kPrefBrowserStartupBlankWindow);
2398 Preferences::RegisterCallback(&ReflectSkeletonUIPrefToRegistry, kPrefThemeId);
2399 Preferences::RegisterCallback(
2400 &ReflectSkeletonUIPrefToRegistry,
2401 nsDependentCString(StaticPrefs::GetPrefName_browser_tabs_inTitlebar()));
2402 }
2403
2404 # if defined(MOZ_LAUNCHER_PROCESS)
2405
OnLauncherPrefChanged(const char * aPref,void * aData)2406 static void OnLauncherPrefChanged(const char* aPref, void* aData) {
2407 bool prefVal = Preferences::GetBool(PREF_WIN_LAUNCHER_PROCESS_ENABLED, true);
2408
2409 mozilla::LauncherRegistryInfo launcherRegInfo;
2410 mozilla::DebugOnly<mozilla::LauncherVoidResult> reflectResult =
2411 launcherRegInfo.ReflectPrefToRegistry(prefVal);
2412 MOZ_ASSERT(reflectResult.inspect().isOk());
2413 }
2414
OnLauncherTelemetryPrefChanged(const char * aPref,void * aData)2415 static void OnLauncherTelemetryPrefChanged(const char* aPref, void* aData) {
2416 bool prefVal = Preferences::GetBool(kPrefHealthReportUploadEnabled, true);
2417
2418 mozilla::LauncherRegistryInfo launcherRegInfo;
2419 mozilla::DebugOnly<mozilla::LauncherVoidResult> reflectResult =
2420 launcherRegInfo.ReflectTelemetryPrefToRegistry(prefVal);
2421 MOZ_ASSERT(reflectResult.inspect().isOk());
2422 }
2423
SetupLauncherProcessPref()2424 static void SetupLauncherProcessPref() {
2425 if (gLauncherProcessState) {
2426 // We've already successfully run
2427 return;
2428 }
2429
2430 mozilla::LauncherRegistryInfo launcherRegInfo;
2431
2432 mozilla::LauncherResult<mozilla::LauncherRegistryInfo::EnabledState>
2433 enabledState = launcherRegInfo.IsEnabled();
2434
2435 if (enabledState.isOk()) {
2436 gLauncherProcessState = Some(enabledState.unwrap());
2437
2438 CrashReporter::AnnotateCrashReport(
2439 CrashReporter::Annotation::LauncherProcessState,
2440 static_cast<uint32_t>(enabledState.unwrap()));
2441
2442 // Reflect the launcher process registry state into user prefs
2443 Preferences::SetBool(
2444 PREF_WIN_LAUNCHER_PROCESS_ENABLED,
2445 enabledState.unwrap() !=
2446 mozilla::LauncherRegistryInfo::EnabledState::ForceDisabled);
2447 }
2448
2449 mozilla::DebugOnly<mozilla::LauncherVoidResult> reflectResult =
2450 launcherRegInfo.ReflectTelemetryPrefToRegistry(
2451 Preferences::GetBool(kPrefHealthReportUploadEnabled, true));
2452 MOZ_ASSERT(reflectResult.inspect().isOk());
2453
2454 Preferences::RegisterCallback(&OnLauncherPrefChanged,
2455 PREF_WIN_LAUNCHER_PROCESS_ENABLED);
2456 Preferences::RegisterCallback(&OnLauncherTelemetryPrefChanged,
2457 kPrefHealthReportUploadEnabled);
2458 }
2459
2460 # endif // defined(MOZ_LAUNCHER_PROCESS)
2461
2462 # if defined(MOZ_DEFAULT_BROWSER_AGENT)
2463
2464 # define DEFAULT_BROWSER_AGENT_KEY_NAME \
2465 "SOFTWARE\\" MOZ_APP_VENDOR "\\" MOZ_APP_NAME "\\Default Browser Agent"
2466
PrependRegistryValueName(nsAutoString & aValueName)2467 static nsresult PrependRegistryValueName(nsAutoString& aValueName) {
2468 nsresult rv;
2469
2470 nsCOMPtr<nsIFile> binaryPath;
2471 rv = XRE_GetBinaryPath(getter_AddRefs(binaryPath));
2472 NS_ENSURE_SUCCESS(rv, rv);
2473
2474 nsCOMPtr<nsIFile> binaryDir;
2475 rv = binaryPath->GetParent(getter_AddRefs(binaryDir));
2476 NS_ENSURE_SUCCESS(rv, rv);
2477
2478 nsAutoString prefix;
2479 rv = binaryDir->GetPath(prefix);
2480 NS_ENSURE_SUCCESS(rv, rv);
2481
2482 prefix.AppendLiteral("|");
2483 aValueName.Insert(prefix, 0);
2484
2485 return NS_OK;
2486 }
2487
OnDefaultAgentTelemetryPrefChanged(const char * aPref,void * aData)2488 static void OnDefaultAgentTelemetryPrefChanged(const char* aPref, void* aData) {
2489 nsresult rv;
2490 nsAutoString valueName;
2491 if (strcmp(aPref, kPrefHealthReportUploadEnabled) == 0) {
2492 valueName.AssignLiteral("DisableTelemetry");
2493 } else if (strcmp(aPref, kPrefDefaultAgentEnabled) == 0) {
2494 valueName.AssignLiteral("DisableDefaultBrowserAgent");
2495 } else {
2496 return;
2497 }
2498 rv = PrependRegistryValueName(valueName);
2499 NS_ENSURE_SUCCESS_VOID(rv);
2500
2501 nsCOMPtr<nsIWindowsRegKey> regKey =
2502 do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv);
2503 NS_ENSURE_SUCCESS_VOID(rv);
2504
2505 nsAutoString keyName;
2506 keyName.AppendLiteral(DEFAULT_BROWSER_AGENT_KEY_NAME);
2507 rv = regKey->Create(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER, keyName,
2508 nsIWindowsRegKey::ACCESS_WRITE);
2509
2510 bool prefVal = Preferences::GetBool(aPref, true);
2511
2512 // We're recording whether the pref is *disabled*, so invert the value.
2513 rv = regKey->WriteIntValue(valueName, prefVal ? 0 : 1);
2514 NS_ENSURE_SUCCESS_VOID(rv);
2515 }
2516
OnSetDefaultBrowserUserChoicePrefChanged(const char * aPref,void * aData)2517 static void OnSetDefaultBrowserUserChoicePrefChanged(const char* aPref,
2518 void* aData) {
2519 nsresult rv;
2520 if (strcmp(aPref, kPrefSetDefaultBrowserUserChoicePref) != 0) {
2521 return;
2522 }
2523 nsAutoString valueName;
2524 valueName.AssignLiteral("SetDefaultBrowserUserChoice");
2525 rv = PrependRegistryValueName(valueName);
2526 NS_ENSURE_SUCCESS_VOID(rv);
2527
2528 nsCOMPtr<nsIWindowsRegKey> regKey =
2529 do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv);
2530 NS_ENSURE_SUCCESS_VOID(rv);
2531
2532 nsAutoString keyName;
2533 keyName.AppendLiteral(DEFAULT_BROWSER_AGENT_KEY_NAME);
2534 rv = regKey->Create(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER, keyName,
2535 nsIWindowsRegKey::ACCESS_WRITE);
2536
2537 bool prefVal = Preferences::GetBool(aPref, true);
2538
2539 rv = regKey->WriteIntValue(valueName, prefVal);
2540 NS_ENSURE_SUCCESS_VOID(rv);
2541 }
2542
OnDefaultAgentRemoteSettingsPrefChanged(const char * aPref,void * aData)2543 static void OnDefaultAgentRemoteSettingsPrefChanged(const char* aPref,
2544 void* aData) {
2545 nsresult rv;
2546 nsAutoString valueName;
2547 if (strcmp(aPref, kPrefServicesSettingsServer) == 0) {
2548 valueName.AssignLiteral("ServicesSettingsServer");
2549 } else if (strcmp(aPref, kPrefSecurityContentSignatureRootHash) == 0) {
2550 valueName.AssignLiteral("SecurityContentSignatureRootHash");
2551 } else {
2552 return;
2553 }
2554 rv = PrependRegistryValueName(valueName);
2555 NS_ENSURE_SUCCESS_VOID(rv);
2556
2557 nsCOMPtr<nsIWindowsRegKey> regKey =
2558 do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv);
2559 NS_ENSURE_SUCCESS_VOID(rv);
2560
2561 nsAutoString keyName;
2562 keyName.AppendLiteral(DEFAULT_BROWSER_AGENT_KEY_NAME);
2563 rv = regKey->Create(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER, keyName,
2564 nsIWindowsRegKey::ACCESS_WRITE);
2565
2566 NS_ENSURE_SUCCESS_VOID(rv);
2567
2568 nsAutoString prefVal;
2569 rv = Preferences::GetString(aPref, prefVal);
2570 NS_ENSURE_SUCCESS_VOID(rv);
2571
2572 if (prefVal.IsEmpty()) {
2573 rv = regKey->RemoveValue(valueName);
2574 } else {
2575 rv = regKey->WriteStringValue(valueName, prefVal);
2576 }
2577 NS_ENSURE_SUCCESS_VOID(rv);
2578 }
2579
SetDefaultAgentLastRunTime()2580 static void SetDefaultAgentLastRunTime() {
2581 nsresult rv;
2582 nsAutoString valueName;
2583 valueName.AppendLiteral("AppLastRunTime");
2584 rv = PrependRegistryValueName(valueName);
2585 NS_ENSURE_SUCCESS_VOID(rv);
2586
2587 nsCOMPtr<nsIWindowsRegKey> regKey =
2588 do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv);
2589 NS_ENSURE_SUCCESS_VOID(rv);
2590
2591 nsAutoString keyName;
2592 keyName.AppendLiteral(DEFAULT_BROWSER_AGENT_KEY_NAME);
2593 rv = regKey->Create(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER, keyName,
2594 nsIWindowsRegKey::ACCESS_WRITE);
2595 NS_ENSURE_SUCCESS_VOID(rv);
2596
2597 FILETIME fileTime;
2598 GetSystemTimeAsFileTime(&fileTime);
2599
2600 ULARGE_INTEGER integerTime;
2601 integerTime.u.LowPart = fileTime.dwLowDateTime;
2602 integerTime.u.HighPart = fileTime.dwHighDateTime;
2603
2604 rv = regKey->WriteInt64Value(valueName, integerTime.QuadPart);
2605 NS_ENSURE_SUCCESS_VOID(rv);
2606 }
2607
2608 # endif // defined(MOZ_DEFAULT_BROWSER_AGENT)
2609
2610 #endif // XP_WIN
2611
UnlockProfile()2612 void UnlockProfile() {
2613 if (gProfileLock) {
2614 gProfileLock->Unlock();
2615 }
2616 }
2617
LaunchChild(bool aBlankCommandLine,bool aTryExec)2618 nsresult LaunchChild(bool aBlankCommandLine, bool aTryExec) {
2619 // Restart this process by exec'ing it into the current process
2620 // if supported by the platform. Otherwise, use NSPR.
2621
2622 #ifdef MOZ_JPROF
2623 // make sure JPROF doesn't think we're E10s
2624 unsetenv("JPROF_ISCHILD");
2625 #endif
2626
2627 if (aBlankCommandLine) {
2628 gRestartArgc = 1;
2629 gRestartArgv[gRestartArgc] = nullptr;
2630 }
2631
2632 SaveToEnv("MOZ_LAUNCHED_CHILD=1");
2633 #if defined(MOZ_LAUNCHER_PROCESS)
2634 SaveToEnv("MOZ_LAUNCHER_PROCESS=1");
2635 #endif // defined(MOZ_LAUNCHER_PROCESS)
2636
2637 #if !defined(MOZ_WIDGET_ANDROID) // Android has separate restart code.
2638 # if defined(XP_MACOSX)
2639 CommandLineServiceMac::SetupMacCommandLine(gRestartArgc, gRestartArgv, true);
2640 LaunchChildMac(gRestartArgc, gRestartArgv);
2641 # else
2642 nsCOMPtr<nsIFile> lf;
2643 nsresult rv = XRE_GetBinaryPath(getter_AddRefs(lf));
2644 if (NS_FAILED(rv)) return rv;
2645
2646 # if defined(XP_WIN)
2647 nsAutoString exePath;
2648 rv = lf->GetPath(exePath);
2649 if (NS_FAILED(rv)) return rv;
2650
2651 HANDLE hProcess;
2652 if (!WinLaunchChild(exePath.get(), gRestartArgc, gRestartArgv, nullptr,
2653 &hProcess))
2654 return NS_ERROR_FAILURE;
2655 // Keep the current process around until the restarted process has created
2656 // its message queue, to avoid the launched process's windows being forced
2657 // into the background.
2658 mozilla::WaitForInputIdle(hProcess);
2659 ::CloseHandle(hProcess);
2660
2661 # else
2662 nsAutoCString exePath;
2663 rv = lf->GetNativePath(exePath);
2664 if (NS_FAILED(rv)) return rv;
2665
2666 # if defined(XP_UNIX)
2667 if (aTryExec) {
2668 execv(exePath.get(), gRestartArgv);
2669
2670 // If execv returns we know it's because it failed.
2671 return NS_ERROR_FAILURE;
2672 }
2673 # endif
2674 if (PR_CreateProcessDetached(exePath.get(), gRestartArgv, nullptr, nullptr) ==
2675 PR_FAILURE) {
2676 return NS_ERROR_FAILURE;
2677 }
2678
2679 // Note that we don't know if the child process starts okay, if it
2680 // immediately returns non-zero then we may mask that by returning a zero
2681 // exit status.
2682
2683 # endif // WP_WIN
2684 # endif // WP_MACOSX
2685 #endif // MOZ_WIDGET_ANDROID
2686
2687 return NS_ERROR_LAUNCHED_CHILD_PROCESS;
2688 }
2689
2690 static const char kProfileProperties[] =
2691 "chrome://mozapps/locale/profile/profileSelection.properties";
2692
2693 namespace {
2694
2695 /**
2696 * This class, instead of a raw nsresult, should be the return type of any
2697 * function called by SelectProfile that initializes XPCOM.
2698 */
2699 class ReturnAbortOnError {
2700 public:
ReturnAbortOnError(nsresult aRv)2701 MOZ_IMPLICIT ReturnAbortOnError(nsresult aRv) { mRv = ConvertRv(aRv); }
2702
operator nsresult()2703 operator nsresult() { return mRv; }
2704
2705 private:
ConvertRv(nsresult aRv)2706 inline nsresult ConvertRv(nsresult aRv) {
2707 if (NS_SUCCEEDED(aRv) || aRv == NS_ERROR_LAUNCHED_CHILD_PROCESS) {
2708 return aRv;
2709 }
2710 #ifdef MOZ_BACKGROUNDTASKS
2711 // A background task that fails to lock its profile will return
2712 // NS_ERROR_UNEXPECTED and this will allow the task to exit with a
2713 // non-zero exit code.
2714 if (aRv == NS_ERROR_UNEXPECTED && BackgroundTasks::IsBackgroundTaskMode()) {
2715 return aRv;
2716 }
2717 #endif
2718 return NS_ERROR_ABORT;
2719 }
2720
2721 nsresult mRv;
2722 };
2723
2724 } // namespace
2725
ProfileMissingDialog(nsINativeAppSupport * aNative)2726 static nsresult ProfileMissingDialog(nsINativeAppSupport* aNative) {
2727 #ifdef MOZ_WIDGET_ANDROID
2728 // We cannot really do anything this early during initialization, so we just
2729 // return as this is likely the effect of misconfiguration on the test side.
2730 // Non-test code paths cannot set the profile folder, which is always the
2731 // default one.
2732 Output(true, "Could not find profile folder.\n");
2733 return NS_ERROR_ABORT;
2734 #else
2735 # ifdef MOZ_BACKGROUNDTASKS
2736 if (BackgroundTasks::IsBackgroundTaskMode()) {
2737 // We should never get to this point in background task mode.
2738 Output(false,
2739 "Could not determine any profile running in backgroundtask mode!\n");
2740 return NS_ERROR_ABORT;
2741 }
2742 # endif // MOZ_BACKGROUNDTASKS
2743
2744 nsresult rv;
2745
2746 ScopedXPCOMStartup xpcom;
2747 rv = xpcom.Initialize();
2748 NS_ENSURE_SUCCESS(rv, rv);
2749
2750 rv = xpcom.SetWindowCreator(aNative);
2751 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
2752
2753 { // extra scoping is needed so we release these components before xpcom
2754 // shutdown
2755 nsCOMPtr<nsIStringBundleService> sbs =
2756 mozilla::components::StringBundle::Service();
2757 NS_ENSURE_TRUE(sbs, NS_ERROR_FAILURE);
2758
2759 nsCOMPtr<nsIStringBundle> sb;
2760 sbs->CreateBundle(kProfileProperties, getter_AddRefs(sb));
2761 NS_ENSURE_TRUE_LOG(sbs, NS_ERROR_FAILURE);
2762
2763 NS_ConvertUTF8toUTF16 appName(gAppData->name);
2764 AutoTArray<nsString, 2> params = {appName, appName};
2765
2766 // profileMissing
2767 nsAutoString missingMessage;
2768 rv = sb->FormatStringFromName("profileMissing", params, missingMessage);
2769 NS_ENSURE_SUCCESS(rv, NS_ERROR_ABORT);
2770
2771 nsAutoString missingTitle;
2772 params.SetLength(1);
2773 rv = sb->FormatStringFromName("profileMissingTitle", params, missingTitle);
2774 NS_ENSURE_SUCCESS(rv, NS_ERROR_ABORT);
2775
2776 nsCOMPtr<nsIPromptService> ps(do_GetService(NS_PROMPTSERVICE_CONTRACTID));
2777 NS_ENSURE_TRUE(ps, NS_ERROR_FAILURE);
2778
2779 ps->Alert(nullptr, missingTitle.get(), missingMessage.get());
2780
2781 return NS_ERROR_ABORT;
2782 }
2783 #endif // MOZ_WIDGET_ANDROID
2784 }
2785
ProfileLockedDialog(nsIFile * aProfileDir,nsIFile * aProfileLocalDir,nsIProfileUnlocker * aUnlocker,nsINativeAppSupport * aNative,nsIProfileLock ** aResult)2786 static ReturnAbortOnError ProfileLockedDialog(nsIFile* aProfileDir,
2787 nsIFile* aProfileLocalDir,
2788 nsIProfileUnlocker* aUnlocker,
2789 nsINativeAppSupport* aNative,
2790 nsIProfileLock** aResult) {
2791 nsresult rv;
2792
2793 bool exists;
2794 aProfileDir->Exists(&exists);
2795 if (!exists) {
2796 return ProfileMissingDialog(aNative);
2797 }
2798
2799 ScopedXPCOMStartup xpcom;
2800 rv = xpcom.Initialize();
2801 NS_ENSURE_SUCCESS(rv, rv);
2802
2803 mozilla::Telemetry::WriteFailedProfileLock(aProfileDir);
2804
2805 rv = xpcom.SetWindowCreator(aNative);
2806 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
2807
2808 { // extra scoping is needed so we release these components before xpcom
2809 // shutdown
2810 nsCOMPtr<nsIStringBundleService> sbs =
2811 mozilla::components::StringBundle::Service();
2812 NS_ENSURE_TRUE(sbs, NS_ERROR_FAILURE);
2813
2814 nsCOMPtr<nsIStringBundle> sb;
2815 sbs->CreateBundle(kProfileProperties, getter_AddRefs(sb));
2816 NS_ENSURE_TRUE_LOG(sbs, NS_ERROR_FAILURE);
2817
2818 NS_ConvertUTF8toUTF16 appName(gAppData->name);
2819 AutoTArray<nsString, 3> params = {appName, appName, appName};
2820
2821 nsAutoString killMessage;
2822 #ifndef XP_MACOSX
2823 rv = sb->FormatStringFromName(
2824 aUnlocker ? "restartMessageUnlocker" : "restartMessageNoUnlocker2",
2825 params, killMessage);
2826 #else
2827 rv = sb->FormatStringFromName(
2828 aUnlocker ? "restartMessageUnlockerMac" : "restartMessageNoUnlockerMac",
2829 params, killMessage);
2830 #endif
2831 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
2832
2833 params.SetLength(1);
2834 nsAutoString killTitle;
2835 rv = sb->FormatStringFromName("restartTitle", params, killTitle);
2836 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
2837
2838 #ifdef MOZ_BACKGROUNDTASKS
2839 if (BackgroundTasks::IsBackgroundTaskMode()) {
2840 // This error is handled specially to exit with a non-zero exit code.
2841 printf_stderr("%s\n", NS_LossyConvertUTF16toASCII(killMessage).get());
2842 return NS_ERROR_UNEXPECTED;
2843 }
2844 #endif
2845
2846 if (gfxPlatform::IsHeadless()) {
2847 // TODO: make a way to turn off all dialogs when headless.
2848 Output(true, "%s\n", NS_LossyConvertUTF16toASCII(killMessage).get());
2849 return NS_ERROR_FAILURE;
2850 }
2851
2852 nsCOMPtr<nsIPromptService> ps(do_GetService(NS_PROMPTSERVICE_CONTRACTID));
2853 NS_ENSURE_TRUE(ps, NS_ERROR_FAILURE);
2854
2855 if (aUnlocker) {
2856 int32_t button;
2857 #ifdef MOZ_WIDGET_ANDROID
2858 // On Android we always kill the process if the lock is still being held
2859 button = 0;
2860 #else
2861 const uint32_t flags = (nsIPromptService::BUTTON_TITLE_IS_STRING *
2862 nsIPromptService::BUTTON_POS_0) +
2863 (nsIPromptService::BUTTON_TITLE_CANCEL *
2864 nsIPromptService::BUTTON_POS_1);
2865
2866 bool checkState = false;
2867 rv = ps->ConfirmEx(nullptr, killTitle.get(), killMessage.get(), flags,
2868 killTitle.get(), nullptr, nullptr, nullptr,
2869 &checkState, &button);
2870 NS_ENSURE_SUCCESS_LOG(rv, rv);
2871 #endif
2872
2873 if (button == 0) {
2874 rv = aUnlocker->Unlock(nsIProfileUnlocker::FORCE_QUIT);
2875 if (NS_FAILED(rv)) {
2876 return rv;
2877 }
2878
2879 SaveFileToEnv("XRE_PROFILE_PATH", aProfileDir);
2880 SaveFileToEnv("XRE_PROFILE_LOCAL_PATH", aProfileLocalDir);
2881
2882 #if defined(MOZ_HAS_REMOTE)
2883 if (gRemoteService) {
2884 gRemoteService->UnlockStartup();
2885 gRemoteService = nullptr;
2886 }
2887 #endif
2888 return LaunchChild(false, true);
2889 }
2890 } else {
2891 rv = ps->Alert(nullptr, killTitle.get(), killMessage.get());
2892 NS_ENSURE_SUCCESS_LOG(rv, rv);
2893 }
2894
2895 return NS_ERROR_ABORT;
2896 }
2897 }
2898
2899 static const char kProfileManagerURL[] =
2900 "chrome://mozapps/content/profile/profileSelection.xhtml";
2901
ShowProfileManager(nsIToolkitProfileService * aProfileSvc,nsINativeAppSupport * aNative)2902 static ReturnAbortOnError ShowProfileManager(
2903 nsIToolkitProfileService* aProfileSvc, nsINativeAppSupport* aNative) {
2904 nsresult rv;
2905
2906 nsCOMPtr<nsIFile> profD, profLD;
2907 bool offline = false;
2908 int32_t dialogReturn;
2909
2910 {
2911 ScopedXPCOMStartup xpcom;
2912 rv = xpcom.Initialize();
2913 NS_ENSURE_SUCCESS(rv, rv);
2914
2915 rv = xpcom.SetWindowCreator(aNative);
2916 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
2917
2918 #ifdef XP_MACOSX
2919 CommandLineServiceMac::SetupMacCommandLine(gRestartArgc, gRestartArgv,
2920 true);
2921 #endif
2922
2923 { // extra scoping is needed so we release these components before xpcom
2924 // shutdown
2925 nsCOMPtr<nsIWindowWatcher> windowWatcher(
2926 do_GetService(NS_WINDOWWATCHER_CONTRACTID));
2927 nsCOMPtr<nsIDialogParamBlock> ioParamBlock(
2928 do_CreateInstance(NS_DIALOGPARAMBLOCK_CONTRACTID));
2929 nsCOMPtr<nsIMutableArray> dlgArray(
2930 do_CreateInstance(NS_ARRAY_CONTRACTID));
2931 NS_ENSURE_TRUE(windowWatcher && ioParamBlock && dlgArray,
2932 NS_ERROR_FAILURE);
2933
2934 ioParamBlock->SetObjects(dlgArray);
2935
2936 nsCOMPtr<nsIAppStartup> appStartup(components::AppStartup::Service());
2937 NS_ENSURE_TRUE(appStartup, NS_ERROR_FAILURE);
2938
2939 nsCOMPtr<mozIDOMWindowProxy> newWindow;
2940 rv = windowWatcher->OpenWindow(
2941 nullptr, nsDependentCString(kProfileManagerURL), "_blank"_ns,
2942 "centerscreen,chrome,modal,titlebar"_ns, ioParamBlock,
2943 getter_AddRefs(newWindow));
2944
2945 NS_ENSURE_SUCCESS_LOG(rv, rv);
2946
2947 rv = ioParamBlock->GetInt(0, &dialogReturn);
2948 if (NS_FAILED(rv) || dialogReturn == nsIToolkitProfileService::exit) {
2949 return NS_ERROR_ABORT;
2950 }
2951
2952 int32_t startOffline;
2953 rv = ioParamBlock->GetInt(1, &startOffline);
2954 offline = NS_SUCCEEDED(rv) && startOffline == 1;
2955
2956 rv = dlgArray->QueryElementAt(0, NS_GET_IID(nsIFile),
2957 getter_AddRefs(profD));
2958 NS_ENSURE_SUCCESS_LOG(rv, rv);
2959
2960 rv = dlgArray->QueryElementAt(1, NS_GET_IID(nsIFile),
2961 getter_AddRefs(profLD));
2962 NS_ENSURE_SUCCESS_LOG(rv, rv);
2963 }
2964 }
2965
2966 if (offline) {
2967 SaveToEnv("XRE_START_OFFLINE=1");
2968 }
2969
2970 // User requested that we restart back into the profile manager.
2971 if (dialogReturn == nsIToolkitProfileService::restart) {
2972 SaveToEnv("XRE_RESTART_TO_PROFILE_MANAGER=1");
2973 SaveToEnv("XRE_RESTARTED_BY_PROFILE_MANAGER=1");
2974 } else {
2975 MOZ_ASSERT(dialogReturn == nsIToolkitProfileService::launchWithProfile);
2976 SaveFileToEnv("XRE_PROFILE_PATH", profD);
2977 SaveFileToEnv("XRE_PROFILE_LOCAL_PATH", profLD);
2978 SaveToEnv("XRE_RESTARTED_BY_PROFILE_MANAGER=1");
2979 }
2980
2981 if (gRestartedByOS) {
2982 // Re-add this argument when actually starting the application.
2983 char** newArgv =
2984 (char**)realloc(gRestartArgv, sizeof(char*) * (gRestartArgc + 2));
2985 NS_ENSURE_TRUE(newArgv, NS_ERROR_OUT_OF_MEMORY);
2986 gRestartArgv = newArgv;
2987 gRestartArgv[gRestartArgc++] = const_cast<char*>("-os-restarted");
2988 gRestartArgv[gRestartArgc] = nullptr;
2989 }
2990 #if defined(MOZ_HAS_REMOTE)
2991 if (gRemoteService) {
2992 gRemoteService->UnlockStartup();
2993 gRemoteService = nullptr;
2994 }
2995 #endif
2996 return LaunchChild(false, true);
2997 }
2998
2999 static bool gDoMigration = false;
3000 static bool gDoProfileReset = false;
3001 static nsCOMPtr<nsIToolkitProfile> gResetOldProfile;
3002
LockProfile(nsINativeAppSupport * aNative,nsIFile * aRootDir,nsIFile * aLocalDir,nsIToolkitProfile * aProfile,nsIProfileLock ** aResult)3003 static nsresult LockProfile(nsINativeAppSupport* aNative, nsIFile* aRootDir,
3004 nsIFile* aLocalDir, nsIToolkitProfile* aProfile,
3005 nsIProfileLock** aResult) {
3006 // If you close Firefox and very quickly reopen it, the old Firefox may
3007 // still be closing down. Rather than immediately showing the
3008 // "Firefox is running but is not responding" message, we spend a few
3009 // seconds retrying first.
3010
3011 static const int kLockRetrySeconds = 5;
3012 static const int kLockRetrySleepMS = 100;
3013
3014 nsresult rv;
3015 nsCOMPtr<nsIProfileUnlocker> unlocker;
3016 const TimeStamp start = TimeStamp::Now();
3017 do {
3018 if (aProfile) {
3019 rv = aProfile->Lock(getter_AddRefs(unlocker), aResult);
3020 } else {
3021 rv = NS_LockProfilePath(aRootDir, aLocalDir, getter_AddRefs(unlocker),
3022 aResult);
3023 }
3024 if (NS_SUCCEEDED(rv)) {
3025 StartupTimeline::Record(StartupTimeline::AFTER_PROFILE_LOCKED);
3026 return NS_OK;
3027 }
3028 PR_Sleep(kLockRetrySleepMS);
3029 } while (TimeStamp::Now() - start <
3030 TimeDuration::FromSeconds(kLockRetrySeconds));
3031
3032 return ProfileLockedDialog(aRootDir, aLocalDir, unlocker, aNative, aResult);
3033 }
3034
3035 // Pick a profile. We need to end up with a profile root dir, local dir and
3036 // potentially an nsIToolkitProfile instance.
3037 //
3038 // 1) check for --profile <path>
3039 // 2) check for -P <name>
3040 // 3) check for --ProfileManager
3041 // 4) use the default profile, if there is one
3042 // 5) if there are *no* profiles, set up profile-migration
3043 // 6) display the profile-manager UI
SelectProfile(nsToolkitProfileService * aProfileSvc,nsINativeAppSupport * aNative,nsIFile ** aRootDir,nsIFile ** aLocalDir,nsIToolkitProfile ** aProfile,bool * aWasDefaultSelection)3044 static nsresult SelectProfile(nsToolkitProfileService* aProfileSvc,
3045 nsINativeAppSupport* aNative, nsIFile** aRootDir,
3046 nsIFile** aLocalDir, nsIToolkitProfile** aProfile,
3047 bool* aWasDefaultSelection) {
3048 StartupTimeline::Record(StartupTimeline::SELECT_PROFILE);
3049
3050 nsresult rv;
3051
3052 if (EnvHasValue("MOZ_RESET_PROFILE_RESTART")) {
3053 gDoProfileReset = true;
3054 gDoMigration = true;
3055 SaveToEnv("MOZ_RESET_PROFILE_RESTART=");
3056 // We only want to restore the previous session if the profile refresh was
3057 // triggered by user. And if it was a user-triggered profile refresh
3058 // through, say, the safeMode dialog or the troubleshooting page, the
3059 // MOZ_RESET_PROFILE_RESTART env variable would be set. Hence we set
3060 // MOZ_RESET_PROFILE_MIGRATE_SESSION here so that Firefox profile migrator
3061 // would migrate old session data later.
3062 SaveToEnv("MOZ_RESET_PROFILE_MIGRATE_SESSION=1");
3063 }
3064
3065 // reset-profile and migration args need to be checked before any profiles are
3066 // chosen below.
3067 ArgResult ar = CheckArg("reset-profile");
3068 if (ar == ARG_FOUND) {
3069 gDoProfileReset = true;
3070 }
3071
3072 ar = CheckArg("migration");
3073 if (ar == ARG_FOUND) {
3074 gDoMigration = true;
3075 }
3076
3077 #if defined(XP_WIN)
3078 // This arg is only used to indicate to telemetry that a profile refresh
3079 // (reset+migration) was requested from the uninstaller, pass this along
3080 // via an environment variable for simplicity.
3081 ar = CheckArg("uninstaller-profile-refresh");
3082 if (ar == ARG_FOUND) {
3083 SaveToEnv("MOZ_UNINSTALLER_PROFILE_REFRESH=1");
3084 }
3085 #endif
3086
3087 if (EnvHasValue("XRE_RESTART_TO_PROFILE_MANAGER")) {
3088 return ShowProfileManager(aProfileSvc, aNative);
3089 }
3090
3091 // Ask the profile manager to select the profile directories to use.
3092 bool didCreate = false;
3093 rv = aProfileSvc->SelectStartupProfile(&gArgc, gArgv, gDoProfileReset,
3094 aRootDir, aLocalDir, aProfile,
3095 &didCreate, aWasDefaultSelection);
3096
3097 if (rv == NS_ERROR_SHOW_PROFILE_MANAGER) {
3098 return ShowProfileManager(aProfileSvc, aNative);
3099 }
3100
3101 NS_ENSURE_SUCCESS(rv, rv);
3102
3103 if (didCreate) {
3104 // For a fresh install, we would like to let users decide
3105 // to do profile migration on their own later after using.
3106 gDoProfileReset = false;
3107 gDoMigration = false;
3108 }
3109
3110 if (gDoProfileReset && !*aProfile) {
3111 NS_WARNING("Profile reset is only supported for named profiles.");
3112 return NS_ERROR_ABORT;
3113 }
3114
3115 // No profile could be found. This generally shouldn't happen, a new profile
3116 // should be created in all cases except for profile reset which is covered
3117 // above, but just in case...
3118 if (!*aRootDir) {
3119 NS_WARNING("Failed to select or create profile.");
3120 return NS_ERROR_ABORT;
3121 }
3122
3123 return NS_OK;
3124 }
3125
3126 #ifdef MOZ_BLOCK_PROFILE_DOWNGRADE
3127 struct FileWriteFunc : public JSONWriteFunc {
3128 FILE* mFile;
FileWriteFuncFileWriteFunc3129 explicit FileWriteFunc(FILE* aFile) : mFile(aFile) {}
3130
WriteFileWriteFunc3131 void Write(const Span<const char>& aStr) override {
3132 fprintf(mFile, "%.*s", int(aStr.size()), aStr.data());
3133 }
3134 };
3135
SubmitDowngradeTelemetry(const nsCString & aLastVersion,bool aHasSync,int32_t aButton)3136 static void SubmitDowngradeTelemetry(const nsCString& aLastVersion,
3137 bool aHasSync, int32_t aButton) {
3138 nsCOMPtr<nsIPrefService> prefSvc =
3139 do_GetService("@mozilla.org/preferences-service;1");
3140 NS_ENSURE_TRUE_VOID(prefSvc);
3141
3142 nsCOMPtr<nsIPrefBranch> prefBranch = do_QueryInterface(prefSvc);
3143 NS_ENSURE_TRUE_VOID(prefBranch);
3144
3145 bool enabled;
3146 nsresult rv =
3147 prefBranch->GetBoolPref(kPrefHealthReportUploadEnabled, &enabled);
3148 NS_ENSURE_SUCCESS_VOID(rv);
3149 if (!enabled) {
3150 return;
3151 }
3152
3153 nsCString server;
3154 rv = prefBranch->GetCharPref("toolkit.telemetry.server", server);
3155 NS_ENSURE_SUCCESS_VOID(rv);
3156
3157 nsCString clientId;
3158 rv = prefBranch->GetCharPref("toolkit.telemetry.cachedClientID", clientId);
3159 NS_ENSURE_SUCCESS_VOID(rv);
3160
3161 rv = prefSvc->GetDefaultBranch(nullptr, getter_AddRefs(prefBranch));
3162 NS_ENSURE_SUCCESS_VOID(rv);
3163
3164 nsCString channel("default");
3165 rv = prefBranch->GetCharPref("app.update.channel", channel);
3166 NS_ENSURE_SUCCESS_VOID(rv);
3167
3168 nsID uuid;
3169 rv = nsID::GenerateUUIDInPlace(uuid);
3170 NS_ENSURE_SUCCESS_VOID(rv);
3171
3172 nsCString arch("null");
3173 nsCOMPtr<nsIPropertyBag2> sysInfo =
3174 do_GetService("@mozilla.org/system-info;1");
3175 NS_ENSURE_TRUE_VOID(sysInfo);
3176 sysInfo->GetPropertyAsACString(u"arch"_ns, arch);
3177
3178 time_t now;
3179 time(&now);
3180 char date[sizeof "YYYY-MM-DDThh:mm:ss.000Z"];
3181 strftime(date, sizeof date, "%FT%T.000Z", gmtime(&now));
3182
3183 NSID_TrimBracketsASCII pingId(uuid);
3184 constexpr auto pingType = "downgrade"_ns;
3185
3186 int32_t pos = aLastVersion.Find("_");
3187 if (pos == kNotFound) {
3188 return;
3189 }
3190
3191 const nsDependentCSubstring lastVersion = Substring(aLastVersion, 0, pos);
3192 const nsDependentCSubstring lastBuildId =
3193 Substring(aLastVersion, pos + 1, 14);
3194
3195 nsPrintfCString url("%s/submit/telemetry/%s/%s/%s/%s/%s/%s?v=%d",
3196 server.get(), PromiseFlatCString(pingId).get(),
3197 pingType.get(), (const char*)gAppData->name,
3198 (const char*)gAppData->version, channel.get(),
3199 (const char*)gAppData->buildID,
3200 TELEMETRY_PING_FORMAT_VERSION);
3201
3202 nsCOMPtr<nsIFile> pingFile;
3203 rv = NS_GetSpecialDirectory(XRE_USER_APP_DATA_DIR, getter_AddRefs(pingFile));
3204 NS_ENSURE_SUCCESS_VOID(rv);
3205 rv = pingFile->Append(u"Pending Pings"_ns);
3206 NS_ENSURE_SUCCESS_VOID(rv);
3207 rv = pingFile->Create(nsIFile::DIRECTORY_TYPE, 0755);
3208 if (NS_FAILED(rv) && rv != NS_ERROR_FILE_ALREADY_EXISTS) {
3209 return;
3210 }
3211 rv = pingFile->Append(NS_ConvertUTF8toUTF16(pingId));
3212 NS_ENSURE_SUCCESS_VOID(rv);
3213
3214 nsCOMPtr<nsIFile> pingSender;
3215 rv = NS_GetSpecialDirectory(NS_GRE_BIN_DIR, getter_AddRefs(pingSender));
3216 NS_ENSURE_SUCCESS_VOID(rv);
3217 # ifdef XP_WIN
3218 pingSender->Append(u"pingsender.exe"_ns);
3219 # else
3220 pingSender->Append(u"pingsender"_ns);
3221 # endif
3222
3223 bool exists;
3224 rv = pingSender->Exists(&exists);
3225 NS_ENSURE_SUCCESS_VOID(rv);
3226 if (!exists) {
3227 return;
3228 }
3229
3230 FILE* file;
3231 rv = pingFile->OpenANSIFileDesc("w", &file);
3232 NS_ENSURE_SUCCESS_VOID(rv);
3233
3234 JSONWriter w(MakeUnique<FileWriteFunc>(file));
3235 w.Start();
3236 {
3237 w.StringProperty("type",
3238 Span<const char>(pingType.Data(), pingType.Length()));
3239 w.StringProperty("id", PromiseFlatCString(pingId));
3240 w.StringProperty("creationDate", MakeStringSpan(date));
3241 w.IntProperty("version", TELEMETRY_PING_FORMAT_VERSION);
3242 w.StringProperty("clientId", clientId);
3243 w.StartObjectProperty("application");
3244 {
3245 w.StringProperty("architecture", arch);
3246 w.StringProperty(
3247 "buildId",
3248 MakeStringSpan(static_cast<const char*>(gAppData->buildID)));
3249 w.StringProperty(
3250 "name", MakeStringSpan(static_cast<const char*>(gAppData->name)));
3251 w.StringProperty(
3252 "version",
3253 MakeStringSpan(static_cast<const char*>(gAppData->version)));
3254 w.StringProperty("displayVersion",
3255 MOZ_STRINGIFY(MOZ_APP_VERSION_DISPLAY));
3256 w.StringProperty(
3257 "vendor", MakeStringSpan(static_cast<const char*>(gAppData->vendor)));
3258 w.StringProperty("platformVersion", gToolkitVersion);
3259 # ifdef TARGET_XPCOM_ABI
3260 w.StringProperty("xpcomAbi", TARGET_XPCOM_ABI);
3261 # else
3262 w.StringProperty("xpcomAbi", "unknown");
3263 # endif
3264 w.StringProperty("channel", channel);
3265 }
3266 w.EndObject();
3267 w.StartObjectProperty("payload");
3268 {
3269 w.StringProperty("lastVersion", PromiseFlatCString(lastVersion));
3270 w.StringProperty("lastBuildId", PromiseFlatCString(lastBuildId));
3271 w.BoolProperty("hasSync", aHasSync);
3272 w.IntProperty("button", aButton);
3273 }
3274 w.EndObject();
3275 }
3276 w.End();
3277
3278 fclose(file);
3279
3280 PathString filePath = pingFile->NativePath();
3281 const filesystem::Path::value_type* args[2];
3282 # ifdef XP_WIN
3283 nsString urlw = NS_ConvertUTF8toUTF16(url);
3284 args[0] = urlw.get();
3285 # else
3286 args[0] = url.get();
3287 # endif
3288 args[1] = filePath.get();
3289
3290 nsCOMPtr<nsIProcess> process =
3291 do_CreateInstance("@mozilla.org/process/util;1");
3292 NS_ENSURE_TRUE_VOID(process);
3293 process->Init(pingSender);
3294 process->SetStartHidden(true);
3295 process->SetNoShell(true);
3296
3297 # ifdef XP_WIN
3298 process->Runw(false, args, 2);
3299 # else
3300 process->Run(false, args, 2);
3301 # endif
3302 }
3303
3304 static const char kProfileDowngradeURL[] =
3305 "chrome://mozapps/content/profile/profileDowngrade.xhtml";
3306
CheckDowngrade(nsIFile * aProfileDir,nsINativeAppSupport * aNative,nsIToolkitProfileService * aProfileSvc,const nsCString & aLastVersion)3307 static ReturnAbortOnError CheckDowngrade(nsIFile* aProfileDir,
3308 nsINativeAppSupport* aNative,
3309 nsIToolkitProfileService* aProfileSvc,
3310 const nsCString& aLastVersion) {
3311 int32_t result = 0;
3312 nsresult rv;
3313
3314 {
3315 if (gfxPlatform::IsHeadless()) {
3316 // TODO: make a way to turn off all dialogs when headless.
3317 Output(true,
3318 "This profile was last used with a newer version of this "
3319 "application. Please create a new profile.\n");
3320 return NS_ERROR_ABORT;
3321 }
3322
3323 ScopedXPCOMStartup xpcom;
3324 rv = xpcom.Initialize();
3325 NS_ENSURE_SUCCESS(rv, rv);
3326
3327 rv = xpcom.SetWindowCreator(aNative);
3328 NS_ENSURE_SUCCESS(rv, rv);
3329
3330 { // extra scoping is needed so we release these components before xpcom
3331 // shutdown
3332 bool hasSync = false;
3333 nsCOMPtr<nsIPrefService> prefSvc =
3334 do_GetService("@mozilla.org/preferences-service;1");
3335 NS_ENSURE_TRUE(prefSvc, rv);
3336
3337 nsCOMPtr<nsIFile> prefsFile;
3338 rv = aProfileDir->Clone(getter_AddRefs(prefsFile));
3339 NS_ENSURE_SUCCESS(rv, rv);
3340
3341 rv = prefsFile->Append(u"prefs.js"_ns);
3342 NS_ENSURE_SUCCESS(rv, rv);
3343
3344 rv = prefSvc->ReadUserPrefsFromFile(prefsFile);
3345 if (NS_SUCCEEDED(rv)) {
3346 nsCOMPtr<nsIPrefBranch> prefBranch = do_QueryInterface(prefSvc);
3347
3348 rv = prefBranch->PrefHasUserValue("services.sync.username", &hasSync);
3349 NS_ENSURE_SUCCESS(rv, rv);
3350 }
3351
3352 nsCOMPtr<nsIWindowWatcher> windowWatcher =
3353 do_GetService(NS_WINDOWWATCHER_CONTRACTID);
3354 NS_ENSURE_TRUE(windowWatcher, NS_ERROR_ABORT);
3355
3356 nsCOMPtr<nsIAppStartup> appStartup(components::AppStartup::Service());
3357 NS_ENSURE_TRUE(appStartup, NS_ERROR_FAILURE);
3358
3359 nsCOMPtr<nsIDialogParamBlock> paramBlock =
3360 do_CreateInstance(NS_DIALOGPARAMBLOCK_CONTRACTID);
3361 NS_ENSURE_TRUE(paramBlock, NS_ERROR_ABORT);
3362
3363 uint8_t flags = 0;
3364 if (hasSync) {
3365 flags |= nsIToolkitProfileService::hasSync;
3366 }
3367
3368 paramBlock->SetInt(0, flags);
3369
3370 nsCOMPtr<mozIDOMWindowProxy> newWindow;
3371 rv = windowWatcher->OpenWindow(
3372 nullptr, nsDependentCString(kProfileDowngradeURL), "_blank"_ns,
3373 "centerscreen,chrome,modal,titlebar"_ns, paramBlock,
3374 getter_AddRefs(newWindow));
3375 NS_ENSURE_SUCCESS(rv, rv);
3376
3377 paramBlock->GetInt(1, &result);
3378
3379 SubmitDowngradeTelemetry(aLastVersion, hasSync, result);
3380 }
3381 }
3382
3383 if (result == nsIToolkitProfileService::createNewProfile) {
3384 // Create a new profile and start it.
3385 nsCString profileName;
3386 profileName.AssignLiteral("default");
3387 # ifdef MOZ_DEDICATED_PROFILES
3388 profileName.Append("-" MOZ_STRINGIFY(MOZ_UPDATE_CHANNEL));
3389 # endif
3390 nsCOMPtr<nsIToolkitProfile> newProfile;
3391 rv = aProfileSvc->CreateUniqueProfile(nullptr, profileName,
3392 getter_AddRefs(newProfile));
3393 NS_ENSURE_SUCCESS(rv, rv);
3394 rv = aProfileSvc->SetDefaultProfile(newProfile);
3395 NS_ENSURE_SUCCESS(rv, rv);
3396 rv = aProfileSvc->Flush();
3397 NS_ENSURE_SUCCESS(rv, rv);
3398
3399 nsCOMPtr<nsIFile> profD, profLD;
3400 rv = newProfile->GetRootDir(getter_AddRefs(profD));
3401 NS_ENSURE_SUCCESS(rv, rv);
3402 rv = newProfile->GetLocalDir(getter_AddRefs(profLD));
3403 NS_ENSURE_SUCCESS(rv, rv);
3404
3405 SaveFileToEnv("XRE_PROFILE_PATH", profD);
3406 SaveFileToEnv("XRE_PROFILE_LOCAL_PATH", profLD);
3407
3408 return LaunchChild(false, true);
3409 }
3410
3411 // Cancel
3412 return NS_ERROR_ABORT;
3413 }
3414 #endif
3415
3416 /**
3417 * Extracts the various parts of a compatibility version string.
3418 *
3419 * Compatibility versions are of the form
3420 * "<appversion>_<appbuildid>/<platformbuildid>". The toolkit version comparator
3421 * can only handle 32-bit numbers and in the normal case build IDs are larger
3422 * than this. So if the build ID is numeric we split it into two version parts.
3423 */
ExtractCompatVersionInfo(const nsACString & aCompatVersion,nsACString & aAppVersion,nsACString & aAppBuildID)3424 static void ExtractCompatVersionInfo(const nsACString& aCompatVersion,
3425 nsACString& aAppVersion,
3426 nsACString& aAppBuildID) {
3427 int32_t underscorePos = aCompatVersion.FindChar('_');
3428 int32_t slashPos = aCompatVersion.FindChar('/');
3429
3430 if (underscorePos == kNotFound || slashPos == kNotFound ||
3431 slashPos < underscorePos) {
3432 NS_WARNING(
3433 "compatibility.ini Version string does not match the expected format.");
3434
3435 // Fall back to just using the entire string as the version.
3436 aAppVersion = aCompatVersion;
3437 aAppBuildID.Truncate(0);
3438 return;
3439 }
3440
3441 aAppVersion = Substring(aCompatVersion, 0, underscorePos);
3442 aAppBuildID = Substring(aCompatVersion, underscorePos + 1,
3443 slashPos - (underscorePos + 1));
3444 }
3445
3446 /**
3447 * Compares the provided compatibility versions. Returns 0 if they match,
3448 * < 0 if the new version is considered an upgrade from the old version and
3449 * > 0 if the new version is considered a downgrade from the old version.
3450 */
CompareCompatVersions(const nsACString & aOldCompatVersion,const nsACString & aNewCompatVersion)3451 int32_t CompareCompatVersions(const nsACString& aOldCompatVersion,
3452 const nsACString& aNewCompatVersion) {
3453 // Hardcode the case where the last run was in safe mode (Bug 1556612). We
3454 // cannot tell if this is a downgrade or not so just assume it isn't and let
3455 // the user proceed.
3456 if (aOldCompatVersion.EqualsLiteral("Safe Mode")) {
3457 return -1;
3458 }
3459
3460 // Extract the major version part from the version string and only use that
3461 // for version comparison.
3462 int32_t index = aOldCompatVersion.FindChar('.');
3463 const nsACString& oldMajorVersion = Substring(
3464 aOldCompatVersion, 0, index < 0 ? aOldCompatVersion.Length() : index);
3465 index = aNewCompatVersion.FindChar('.');
3466 const nsACString& newMajorVersion = Substring(
3467 aNewCompatVersion, 0, index < 0 ? aNewCompatVersion.Length() : index);
3468
3469 return CompareVersions(PromiseFlatCString(oldMajorVersion).get(),
3470 PromiseFlatCString(newMajorVersion).get());
3471 }
3472
3473 /**
3474 * Checks the compatibility.ini file to see if we have updated our application
3475 * or otherwise invalidated our caches. If the application has been updated,
3476 * we return false; otherwise, we return true.
3477 *
3478 * We also write the status of the caches (valid/invalid) into the return param
3479 * aCachesOK. The aCachesOK is always invalid if the application has been
3480 * updated.
3481 *
3482 * Finally, aIsDowngrade is set to true if the current application is older
3483 * than that previously used by the profile.
3484 */
CheckCompatibility(nsIFile * aProfileDir,const nsCString & aVersion,const nsCString & aOSABI,nsIFile * aXULRunnerDir,nsIFile * aAppDir,nsIFile * aFlagFile,bool * aCachesOK,bool * aIsDowngrade,nsCString & aLastVersion)3485 static bool CheckCompatibility(nsIFile* aProfileDir, const nsCString& aVersion,
3486 const nsCString& aOSABI, nsIFile* aXULRunnerDir,
3487 nsIFile* aAppDir, nsIFile* aFlagFile,
3488 bool* aCachesOK, bool* aIsDowngrade,
3489 nsCString& aLastVersion) {
3490 *aCachesOK = false;
3491 *aIsDowngrade = false;
3492 gLastAppVersion.SetIsVoid(true);
3493 gLastAppBuildID.SetIsVoid(true);
3494
3495 nsCOMPtr<nsIFile> file;
3496 aProfileDir->Clone(getter_AddRefs(file));
3497 if (!file) return false;
3498 file->AppendNative(FILE_COMPATIBILITY_INFO);
3499
3500 nsINIParser parser;
3501 nsresult rv = parser.Init(file);
3502 if (NS_FAILED(rv)) return false;
3503
3504 rv = parser.GetString("Compatibility", "LastVersion", aLastVersion);
3505 if (NS_FAILED(rv)) {
3506 return false;
3507 }
3508
3509 if (!aLastVersion.Equals(aVersion)) {
3510 // The version is not the same. Whether it's a downgrade depends on an
3511 // actual comparison:
3512 *aIsDowngrade = 0 < CompareCompatVersions(aLastVersion, aVersion);
3513 ExtractCompatVersionInfo(aLastVersion, gLastAppVersion, gLastAppBuildID);
3514 return false;
3515 }
3516
3517 // If we get here, the version matched, but there may still be other
3518 // differences between us and the build that the profile last ran under.
3519
3520 gLastAppVersion.Assign(gAppData->version);
3521 gLastAppBuildID.Assign(gAppData->buildID);
3522
3523 nsAutoCString buf;
3524 rv = parser.GetString("Compatibility", "LastOSABI", buf);
3525 if (NS_FAILED(rv) || !aOSABI.Equals(buf)) return false;
3526
3527 rv = parser.GetString("Compatibility", "LastPlatformDir", buf);
3528 if (NS_FAILED(rv)) return false;
3529
3530 nsCOMPtr<nsIFile> lf;
3531 rv = NS_NewNativeLocalFile(""_ns, false, getter_AddRefs(lf));
3532 if (NS_FAILED(rv)) return false;
3533
3534 rv = lf->SetPersistentDescriptor(buf);
3535 if (NS_FAILED(rv)) return false;
3536
3537 bool eq;
3538 rv = lf->Equals(aXULRunnerDir, &eq);
3539 if (NS_FAILED(rv) || !eq) return false;
3540
3541 if (aAppDir) {
3542 rv = parser.GetString("Compatibility", "LastAppDir", buf);
3543 if (NS_FAILED(rv)) return false;
3544
3545 rv = NS_NewNativeLocalFile(""_ns, false, getter_AddRefs(lf));
3546 if (NS_FAILED(rv)) return false;
3547
3548 rv = lf->SetPersistentDescriptor(buf);
3549 if (NS_FAILED(rv)) return false;
3550
3551 rv = lf->Equals(aAppDir, &eq);
3552 if (NS_FAILED(rv) || !eq) return false;
3553 }
3554
3555 // If we see this flag, caches are invalid.
3556 rv = parser.GetString("Compatibility", "InvalidateCaches", buf);
3557 *aCachesOK = (NS_FAILED(rv) || !buf.EqualsLiteral("1"));
3558
3559 bool purgeCaches = false;
3560 if (aFlagFile && NS_SUCCEEDED(aFlagFile->Exists(&purgeCaches)) &&
3561 purgeCaches) {
3562 *aCachesOK = false;
3563 }
3564
3565 return true;
3566 }
3567
BuildCompatVersion(const char * aAppVersion,const char * aAppBuildID,const char * aToolkitBuildID,nsACString & aBuf)3568 void BuildCompatVersion(const char* aAppVersion, const char* aAppBuildID,
3569 const char* aToolkitBuildID, nsACString& aBuf) {
3570 aBuf.Assign(aAppVersion);
3571 aBuf.Append('_');
3572 aBuf.Append(aAppBuildID);
3573 aBuf.Append('/');
3574 aBuf.Append(aToolkitBuildID);
3575 }
3576
BuildVersion(nsCString & aBuf)3577 static void BuildVersion(nsCString& aBuf) {
3578 BuildCompatVersion(gAppData->version, gAppData->buildID, gToolkitBuildID,
3579 aBuf);
3580 }
3581
WriteVersion(nsIFile * aProfileDir,const nsCString & aVersion,const nsCString & aOSABI,nsIFile * aXULRunnerDir,nsIFile * aAppDir,bool invalidateCache)3582 static void WriteVersion(nsIFile* aProfileDir, const nsCString& aVersion,
3583 const nsCString& aOSABI, nsIFile* aXULRunnerDir,
3584 nsIFile* aAppDir, bool invalidateCache) {
3585 nsCOMPtr<nsIFile> file;
3586 aProfileDir->Clone(getter_AddRefs(file));
3587 if (!file) return;
3588 file->AppendNative(FILE_COMPATIBILITY_INFO);
3589
3590 nsAutoCString platformDir;
3591 Unused << aXULRunnerDir->GetPersistentDescriptor(platformDir);
3592
3593 nsAutoCString appDir;
3594 if (aAppDir) Unused << aAppDir->GetPersistentDescriptor(appDir);
3595
3596 PRFileDesc* fd;
3597 nsresult rv = file->OpenNSPRFileDesc(PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE,
3598 0600, &fd);
3599 if (NS_FAILED(rv)) {
3600 NS_ERROR("could not create output stream");
3601 return;
3602 }
3603
3604 static const char kHeader[] = "[Compatibility]" NS_LINEBREAK "LastVersion=";
3605
3606 PR_Write(fd, kHeader, sizeof(kHeader) - 1);
3607 PR_Write(fd, aVersion.get(), aVersion.Length());
3608
3609 static const char kOSABIHeader[] = NS_LINEBREAK "LastOSABI=";
3610 PR_Write(fd, kOSABIHeader, sizeof(kOSABIHeader) - 1);
3611 PR_Write(fd, aOSABI.get(), aOSABI.Length());
3612
3613 static const char kPlatformDirHeader[] = NS_LINEBREAK "LastPlatformDir=";
3614
3615 PR_Write(fd, kPlatformDirHeader, sizeof(kPlatformDirHeader) - 1);
3616 PR_Write(fd, platformDir.get(), platformDir.Length());
3617
3618 static const char kAppDirHeader[] = NS_LINEBREAK "LastAppDir=";
3619 if (aAppDir) {
3620 PR_Write(fd, kAppDirHeader, sizeof(kAppDirHeader) - 1);
3621 PR_Write(fd, appDir.get(), appDir.Length());
3622 }
3623
3624 static const char kInvalidationHeader[] = NS_LINEBREAK "InvalidateCaches=1";
3625 if (invalidateCache)
3626 PR_Write(fd, kInvalidationHeader, sizeof(kInvalidationHeader) - 1);
3627
3628 static const char kNL[] = NS_LINEBREAK;
3629 PR_Write(fd, kNL, sizeof(kNL) - 1);
3630
3631 PR_Close(fd);
3632 }
3633
3634 /**
3635 * Returns true if the startup cache file was successfully removed.
3636 * Returns false if file->Clone fails at any point (OOM) or if unable
3637 * to remove the startup cache file. Note in particular the return value
3638 * is unaffected by a failure to remove extensions.ini
3639 */
RemoveComponentRegistries(nsIFile * aProfileDir,nsIFile * aLocalProfileDir,bool aRemoveEMFiles)3640 static bool RemoveComponentRegistries(nsIFile* aProfileDir,
3641 nsIFile* aLocalProfileDir,
3642 bool aRemoveEMFiles) {
3643 nsCOMPtr<nsIFile> file;
3644 aProfileDir->Clone(getter_AddRefs(file));
3645 if (!file) return false;
3646
3647 if (aRemoveEMFiles) {
3648 file->SetNativeLeafName("extensions.ini"_ns);
3649 file->Remove(false);
3650 }
3651
3652 aLocalProfileDir->Clone(getter_AddRefs(file));
3653 if (!file) return false;
3654
3655 #if defined(XP_UNIX) || defined(XP_BEOS)
3656 # define PLATFORM_FASL_SUFFIX ".mfasl"
3657 #elif defined(XP_WIN)
3658 # define PLATFORM_FASL_SUFFIX ".mfl"
3659 #endif
3660
3661 file->AppendNative(nsLiteralCString("XUL" PLATFORM_FASL_SUFFIX));
3662 file->Remove(false);
3663
3664 file->SetNativeLeafName(nsLiteralCString("XPC" PLATFORM_FASL_SUFFIX));
3665 file->Remove(false);
3666
3667 file->SetNativeLeafName("startupCache"_ns);
3668 nsresult rv = file->Remove(true);
3669 return NS_SUCCEEDED(rv) || rv == NS_ERROR_FILE_TARGET_DOES_NOT_EXIST ||
3670 rv == NS_ERROR_FILE_NOT_FOUND;
3671 }
3672
3673 // When we first initialize the crash reporter we don't have a profile,
3674 // so we set the minidump path to $TEMP. Once we have a profile,
3675 // we set it to $PROFILE/minidumps, creating the directory
3676 // if needed.
MakeOrSetMinidumpPath(nsIFile * profD)3677 static void MakeOrSetMinidumpPath(nsIFile* profD) {
3678 nsCOMPtr<nsIFile> dumpD;
3679 profD->Clone(getter_AddRefs(dumpD));
3680
3681 if (dumpD) {
3682 bool fileExists;
3683 // XXX: do some more error checking here
3684 dumpD->Append(u"minidumps"_ns);
3685 dumpD->Exists(&fileExists);
3686 if (!fileExists) {
3687 nsresult rv = dumpD->Create(nsIFile::DIRECTORY_TYPE, 0700);
3688 NS_ENSURE_SUCCESS_VOID(rv);
3689 }
3690
3691 nsAutoString pathStr;
3692 if (NS_SUCCEEDED(dumpD->GetPath(pathStr)))
3693 CrashReporter::SetMinidumpPath(pathStr);
3694 }
3695 }
3696
3697 const XREAppData* gAppData = nullptr;
3698
3699 /**
3700 * NSPR will search for the "nspr_use_zone_allocator" symbol throughout
3701 * the process and use it to determine whether the application defines its own
3702 * memory allocator or not.
3703 *
3704 * Since most applications (e.g. Firefox and Thunderbird) don't use any special
3705 * allocators and therefore don't define this symbol, NSPR must search the
3706 * entire process, which reduces startup performance.
3707 *
3708 * By defining the symbol here, we can avoid the wasted lookup and hopefully
3709 * improve startup performance.
3710 */
3711 NS_VISIBILITY_DEFAULT PRBool nspr_use_zone_allocator = PR_FALSE;
3712
3713 #ifdef CAIRO_HAS_DWRITE_FONT
3714
3715 # include <dwrite.h>
3716 # include "nsWindowsHelpers.h"
3717
3718 # ifdef DEBUG_DWRITE_STARTUP
3719
3720 # define LOGREGISTRY(msg) LogRegistryEvent(msg)
3721
3722 // for use when monitoring process
LogRegistryEvent(const wchar_t * msg)3723 static void LogRegistryEvent(const wchar_t* msg) {
3724 HKEY dummyKey;
3725 HRESULT hr;
3726 wchar_t buf[512];
3727
3728 wsprintf(buf, L" log %s", msg);
3729 hr = RegOpenKeyEx(HKEY_LOCAL_MACHINE, buf, 0, KEY_READ, &dummyKey);
3730 if (SUCCEEDED(hr)) {
3731 RegCloseKey(dummyKey);
3732 }
3733 }
3734 # else
3735
3736 # define LOGREGISTRY(msg)
3737
3738 # endif
3739
InitDwriteBG(LPVOID lpdwThreadParam)3740 static DWORD WINAPI InitDwriteBG(LPVOID lpdwThreadParam) {
3741 SetThreadPriority(GetCurrentThread(), THREAD_MODE_BACKGROUND_BEGIN);
3742 LOGREGISTRY(L"loading dwrite.dll");
3743 HMODULE dwdll = LoadLibrarySystem32(L"dwrite.dll");
3744 if (dwdll) {
3745 decltype(DWriteCreateFactory)* createDWriteFactory =
3746 (decltype(DWriteCreateFactory)*)GetProcAddress(dwdll,
3747 "DWriteCreateFactory");
3748 if (createDWriteFactory) {
3749 LOGREGISTRY(L"creating dwrite factory");
3750 IDWriteFactory* factory;
3751 HRESULT hr = createDWriteFactory(DWRITE_FACTORY_TYPE_SHARED,
3752 __uuidof(IDWriteFactory),
3753 reinterpret_cast<IUnknown**>(&factory));
3754 if (SUCCEEDED(hr)) {
3755 LOGREGISTRY(L"dwrite factory done");
3756 factory->Release();
3757 LOGREGISTRY(L"freed factory");
3758 } else {
3759 LOGREGISTRY(L"failed to create factory");
3760 }
3761 }
3762 }
3763 SetThreadPriority(GetCurrentThread(), THREAD_MODE_BACKGROUND_END);
3764 return 0;
3765 }
3766 #endif
3767
3768 #ifdef USE_GLX_TEST
3769 bool fire_glxtest_process();
3770 #endif
3771
3772 #include "GeckoProfiler.h"
3773 #include "ProfilerControl.h"
3774
3775 // Encapsulates startup and shutdown state for XRE_main
3776 class XREMain {
3777 public:
XREMain()3778 XREMain()
3779 : mStartOffline(false),
3780 mShuttingDown(false)
3781 #ifdef MOZ_HAS_REMOTE
3782 ,
3783 mDisableRemoteClient(false),
3784 mDisableRemoteServer(false)
3785 #endif
3786 #if defined(MOZ_WIDGET_GTK)
3787 ,
3788 mGdkDisplay(nullptr)
3789 #endif
3790 {};
3791
~XREMain()3792 ~XREMain() {
3793 mScopedXPCOM = nullptr;
3794 mAppData = nullptr;
3795 }
3796
3797 int XRE_main(int argc, char* argv[], const BootstrapConfig& aConfig);
3798 int XRE_mainInit(bool* aExitFlag);
3799 int XRE_mainStartup(bool* aExitFlag);
3800 nsresult XRE_mainRun();
3801
3802 Result<bool, nsresult> CheckLastStartupWasCrash();
3803
3804 nsCOMPtr<nsINativeAppSupport> mNativeApp;
3805 RefPtr<nsToolkitProfileService> mProfileSvc;
3806 nsCOMPtr<nsIFile> mProfD;
3807 nsCOMPtr<nsIFile> mProfLD;
3808 nsCOMPtr<nsIProfileLock> mProfileLock;
3809 #if defined(MOZ_HAS_REMOTE)
3810 RefPtr<nsRemoteService> mRemoteService;
3811 #endif
3812
3813 UniquePtr<ScopedXPCOMStartup> mScopedXPCOM;
3814 UniquePtr<XREAppData> mAppData;
3815
3816 nsXREDirProvider mDirProvider;
3817 nsAutoCString mDesktopStartupID;
3818
3819 bool mStartOffline;
3820 bool mShuttingDown;
3821 #if defined(MOZ_HAS_REMOTE)
3822 bool mDisableRemoteClient;
3823 bool mDisableRemoteServer;
3824 #endif
3825
3826 #if defined(MOZ_WIDGET_GTK)
3827 GdkDisplay* mGdkDisplay;
3828 #endif
3829 };
3830
3831 #if defined(XP_UNIX) && !defined(ANDROID)
FormatUid(uid_t aId)3832 static SmprintfPointer FormatUid(uid_t aId) {
3833 if (const auto pw = getpwuid(aId)) {
3834 return mozilla::Smprintf("%s", pw->pw_name);
3835 }
3836 return mozilla::Smprintf("uid %d", static_cast<int>(aId));
3837 }
3838
3839 // Bug 1323302: refuse to run under sudo or similar.
CheckForUserMismatch()3840 static bool CheckForUserMismatch() {
3841 static char const* const kVars[] = {
3842 "HOME",
3843 # ifdef MOZ_WIDGET_GTK
3844 "XDG_RUNTIME_DIR",
3845 # endif
3846 # ifdef MOZ_X11
3847 "XAUTHORITY",
3848 # endif
3849 };
3850
3851 const uid_t euid = geteuid();
3852 if (euid != 0) {
3853 // On Linux it's possible to have superuser capabilities with a
3854 // nonzero uid, but anyone who knows enough to make that happen
3855 // probably knows enough to debug the resulting problems.
3856 // Otherwise, a non-root user can't cause the problems we're
3857 // concerned about.
3858 return false;
3859 }
3860
3861 for (const auto var : kVars) {
3862 if (const auto path = PR_GetEnv(var)) {
3863 struct stat st;
3864 if (stat(path, &st) == 0) {
3865 if (st.st_uid != euid) {
3866 const auto owner = FormatUid(st.st_uid);
3867 Output(true,
3868 "Running " MOZ_APP_DISPLAYNAME
3869 " as root in a regular"
3870 " user's session is not supported. ($%s is %s which is"
3871 " owned by %s.)\n",
3872 var, path, owner.get());
3873 return true;
3874 }
3875 }
3876 }
3877 }
3878 return false;
3879 }
3880 #else // !XP_UNIX || ANDROID
CheckForUserMismatch()3881 static bool CheckForUserMismatch() { return false; }
3882 #endif
3883
IncreaseDescriptorLimits()3884 static void IncreaseDescriptorLimits() {
3885 #ifdef XP_UNIX
3886 // Increase the fd limit to accomodate IPC resources like shared memory.
3887 // See also the Darwin case in config/external/nspr/pr/moz.build
3888 static const rlim_t kFDs = 4096;
3889 struct rlimit rlim;
3890
3891 if (getrlimit(RLIMIT_NOFILE, &rlim) != 0) {
3892 Output(false, "getrlimit: %s\n", strerror(errno));
3893 return;
3894 }
3895 // Don't decrease the limit if it's already high enough, but don't
3896 // try to go over the hard limit. (RLIM_INFINITY isn't required to
3897 // be the numerically largest rlim_t, so don't assume that.)
3898 if (rlim.rlim_cur != RLIM_INFINITY && rlim.rlim_cur < kFDs &&
3899 rlim.rlim_cur < rlim.rlim_max) {
3900 if (rlim.rlim_max != RLIM_INFINITY && rlim.rlim_max < kFDs) {
3901 rlim.rlim_cur = rlim.rlim_max;
3902 } else {
3903 rlim.rlim_cur = kFDs;
3904 }
3905 if (setrlimit(RLIMIT_NOFILE, &rlim) != 0) {
3906 Output(false, "setrlimit: %s\n", strerror(errno));
3907 }
3908 }
3909 #endif
3910 }
3911
3912 /*
3913 * XRE_mainInit - Initial setup and command line parameter processing.
3914 * Main() will exit early if either return value != 0 or if aExitFlag is
3915 * true.
3916 */
XRE_mainInit(bool * aExitFlag)3917 int XREMain::XRE_mainInit(bool* aExitFlag) {
3918 if (!aExitFlag) return 1;
3919 *aExitFlag = false;
3920
3921 atexit(UnexpectedExit);
3922 auto expectedShutdown = mozilla::MakeScopeExit([&] { MozExpectedExit(); });
3923
3924 StartupTimeline::Record(StartupTimeline::MAIN);
3925
3926 if (CheckForUserMismatch()) {
3927 return 1;
3928 }
3929
3930 #ifdef XP_MACOSX
3931 mozilla::MacAutoreleasePool pool;
3932
3933 DisableAppNap();
3934 #endif
3935
3936 #ifdef MOZ_BACKGROUNDTASKS
3937 Maybe<nsCString> backgroundTask = Nothing();
3938 const char* backgroundTaskName = nullptr;
3939 if (ARG_FOUND ==
3940 CheckArg("backgroundtask", &backgroundTaskName, CheckArgFlag::None)) {
3941 backgroundTask = Some(backgroundTaskName);
3942 }
3943 BackgroundTasks::Init(backgroundTask);
3944
3945 if (BackgroundTasks::IsBackgroundTaskMode()) {
3946 printf_stderr("*** You are running in background task mode. ***\n");
3947 }
3948 #endif
3949
3950 #ifndef ANDROID
3951 if (PR_GetEnv("MOZ_RUN_GTEST")
3952 # ifdef FUZZING
3953 || PR_GetEnv("FUZZER")
3954 # endif
3955 # ifdef MOZ_BACKGROUNDTASKS
3956 || BackgroundTasks::IsBackgroundTaskMode()
3957 # endif
3958 ) {
3959 // Enable headless mode and assert that it worked, since gfxPlatform
3960 // uses a static bool set after the first call to `IsHeadless`.
3961 // Note: Android gtests seem to require an Activity and fail to start
3962 // with headless mode enabled.
3963 PR_SetEnv("MOZ_HEADLESS=1");
3964 MOZ_ASSERT(gfxPlatform::IsHeadless());
3965 }
3966 #endif // ANDROID
3967
3968 if (PR_GetEnv("MOZ_CHAOSMODE")) {
3969 ChaosFeature feature = ChaosFeature::Any;
3970 long featureInt = strtol(PR_GetEnv("MOZ_CHAOSMODE"), nullptr, 16);
3971 if (featureInt) {
3972 // NOTE: MOZ_CHAOSMODE=0 or a non-hex value maps to Any feature.
3973 feature = static_cast<ChaosFeature>(featureInt);
3974 }
3975 ChaosMode::SetChaosFeature(feature);
3976 }
3977
3978 if (CheckArgExists("fxr")) {
3979 gFxREmbedded = true;
3980 }
3981
3982 if (ChaosMode::isActive(ChaosFeature::Any)) {
3983 printf_stderr(
3984 "*** You are running in chaos test mode. See ChaosMode.h. ***\n");
3985 }
3986
3987 if (CheckArg("headless") || CheckArgExists("screenshot")) {
3988 PR_SetEnv("MOZ_HEADLESS=1");
3989 }
3990
3991 if (gfxPlatform::IsHeadless()) {
3992 #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) || defined(XP_MACOSX)
3993 printf_stderr("*** You are running in headless mode.\n");
3994 #else
3995 Output(
3996 true,
3997 "Error: headless mode is not currently supported on this platform.\n");
3998 return 1;
3999 #endif
4000
4001 #ifdef XP_MACOSX
4002 // To avoid taking focus when running in headless mode immediately
4003 // transition Firefox to a background application.
4004 ProcessSerialNumber psn = {0, kCurrentProcess};
4005 OSStatus transformStatus =
4006 TransformProcessType(&psn, kProcessTransformToBackgroundApplication);
4007 if (transformStatus != noErr) {
4008 NS_ERROR("Failed to make process a background application.");
4009 return 1;
4010 }
4011 #endif
4012 }
4013
4014 nsresult rv;
4015 ArgResult ar;
4016
4017 #ifdef DEBUG
4018 if (PR_GetEnv("XRE_MAIN_BREAK")) NS_BREAK();
4019 #endif
4020
4021 IncreaseDescriptorLimits();
4022
4023 #ifdef USE_GLX_TEST
4024 // bug 639842 - it's very important to fire this process BEFORE we set up
4025 // error handling. indeed, this process is expected to be crashy, and we
4026 // don't want the user to see its crashes. That's the whole reason for
4027 // doing this in a separate process.
4028 //
4029 // This call will cause a fork and the fork will terminate itself separately
4030 // from the usual shutdown sequence
4031 fire_glxtest_process();
4032 #endif
4033
4034 SetupErrorHandling(gArgv[0]);
4035
4036 #ifdef CAIRO_HAS_DWRITE_FONT
4037 {
4038 // Bug 602792 - when DWriteCreateFactory is called the dwrite client dll
4039 // starts the FntCache service if it isn't already running (it's set
4040 // to manual startup by default in Windows 7 RTM). Subsequent DirectWrite
4041 // calls cause the IDWriteFactory object to communicate with the FntCache
4042 // service with a timeout; if there's no response after the timeout, the
4043 // DirectWrite client library will assume the service isn't around and do
4044 // manual font file I/O on _all_ system fonts. To avoid this, load the
4045 // dwrite library and create a factory as early as possible so that the
4046 // FntCache service is ready by the time it's needed.
4047
4048 CreateThread(nullptr, 0, &InitDwriteBG, nullptr, 0, nullptr);
4049 }
4050 #endif
4051
4052 #ifdef XP_UNIX
4053 const char* home = PR_GetEnv("HOME");
4054 if (!home || !*home) {
4055 struct passwd* pw = getpwuid(geteuid());
4056 if (!pw || !pw->pw_dir) {
4057 Output(true, "Could not determine HOME directory");
4058 return 1;
4059 }
4060 SaveWordToEnv("HOME", nsDependentCString(pw->pw_dir));
4061 }
4062 #endif
4063
4064 #ifdef MOZ_ACCESSIBILITY_ATK
4065 // Suppress atk-bridge init at startup, until mozilla accessibility is
4066 // initialized. This works after gnome 2.24.2.
4067 SaveToEnv("NO_AT_BRIDGE=1");
4068 #endif
4069
4070 // Check for application.ini overrides
4071 const char* override = nullptr;
4072 ar = CheckArg("override", &override);
4073 if (ar == ARG_BAD) {
4074 Output(true, "Incorrect number of arguments passed to --override");
4075 return 1;
4076 }
4077 if (ar == ARG_FOUND) {
4078 nsCOMPtr<nsIFile> overrideLF;
4079 rv = XRE_GetFileFromPath(override, getter_AddRefs(overrideLF));
4080 if (NS_FAILED(rv)) {
4081 Output(true, "Error: unrecognized override.ini path.\n");
4082 return 1;
4083 }
4084
4085 rv = XRE_ParseAppData(overrideLF, *mAppData);
4086 if (NS_FAILED(rv)) {
4087 Output(true, "Couldn't read override.ini");
4088 return 1;
4089 }
4090 }
4091
4092 // Check sanity and correctness of app data.
4093
4094 if (!mAppData->name) {
4095 Output(true, "Error: App:Name not specified in application.ini\n");
4096 return 1;
4097 }
4098 if (!mAppData->buildID) {
4099 Output(true, "Error: App:BuildID not specified in application.ini\n");
4100 return 1;
4101 }
4102
4103 // XXX Originally ScopedLogging was here? Now it's in XRE_main above
4104 // XRE_mainInit.
4105
4106 if (!mAppData->minVersion) {
4107 Output(true, "Error: Gecko:MinVersion not specified in application.ini\n");
4108 return 1;
4109 }
4110
4111 if (!mAppData->maxVersion) {
4112 // If no maxVersion is specified, we assume the app is only compatible
4113 // with the initial preview release. Do not increment this number ever!
4114 mAppData->maxVersion = "1.*";
4115 }
4116
4117 if (mozilla::Version(mAppData->minVersion) > gToolkitVersion ||
4118 mozilla::Version(mAppData->maxVersion) < gToolkitVersion) {
4119 Output(true,
4120 "Error: Platform version '%s' is not compatible with\n"
4121 "minVersion >= %s\nmaxVersion <= %s\n",
4122 (const char*)gToolkitVersion, (const char*)mAppData->minVersion,
4123 (const char*)mAppData->maxVersion);
4124 return 1;
4125 }
4126
4127 rv = mDirProvider.Initialize(mAppData->directory, mAppData->xreDirectory);
4128 if (NS_FAILED(rv)) return 1;
4129
4130 if (EnvHasValue("MOZ_CRASHREPORTER")) {
4131 mAppData->flags |= NS_XRE_ENABLE_CRASH_REPORTER;
4132 }
4133
4134 nsCOMPtr<nsIFile> xreBinDirectory;
4135 xreBinDirectory = mDirProvider.GetGREBinDir();
4136
4137 if ((mAppData->flags & NS_XRE_ENABLE_CRASH_REPORTER) &&
4138 NS_SUCCEEDED(CrashReporter::SetExceptionHandler(xreBinDirectory))) {
4139 nsCOMPtr<nsIFile> file;
4140 rv = nsXREDirProvider::GetUserAppDataDirectory(getter_AddRefs(file));
4141 if (NS_SUCCEEDED(rv)) {
4142 CrashReporter::SetUserAppDataDirectory(file);
4143 }
4144 if (mAppData->crashReporterURL)
4145 CrashReporter::SetServerURL(
4146 nsDependentCString(mAppData->crashReporterURL));
4147
4148 // We overwrite this once we finish starting up.
4149 CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::StartupCrash,
4150 true);
4151
4152 // pass some basic info from the app data
4153 if (mAppData->vendor)
4154 CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::Vendor,
4155 nsDependentCString(mAppData->vendor));
4156 if (mAppData->name)
4157 CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::ProductName,
4158 nsDependentCString(mAppData->name));
4159 if (mAppData->ID)
4160 CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::ProductID,
4161 nsDependentCString(mAppData->ID));
4162 if (mAppData->version)
4163 CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::Version,
4164 nsDependentCString(mAppData->version));
4165 if (mAppData->buildID)
4166 CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::BuildID,
4167 nsDependentCString(mAppData->buildID));
4168
4169 nsDependentCString releaseChannel(MOZ_STRINGIFY(MOZ_UPDATE_CHANNEL));
4170 CrashReporter::AnnotateCrashReport(
4171 CrashReporter::Annotation::ReleaseChannel, releaseChannel);
4172 #ifdef MOZ_LINKER
4173 CrashReporter::AnnotateCrashReport(
4174 CrashReporter::Annotation::CrashAddressLikelyWrong,
4175 IsSignalHandlingBroken());
4176 #endif
4177
4178 #ifdef XP_WIN
4179 nsAutoString appInitDLLs;
4180 if (widget::WinUtils::GetAppInitDLLs(appInitDLLs)) {
4181 CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::AppInitDLLs,
4182 NS_ConvertUTF16toUTF8(appInitDLLs));
4183 }
4184
4185 nsString packageFamilyName = widget::WinUtils::GetPackageFamilyName();
4186 if (StringBeginsWith(packageFamilyName, u"Mozilla."_ns) ||
4187 StringBeginsWith(packageFamilyName, u"MozillaCorporation."_ns)) {
4188 CrashReporter::AnnotateCrashReport(
4189 CrashReporter::Annotation::WindowsPackageFamilyName,
4190 NS_ConvertUTF16toUTF8(packageFamilyName));
4191 }
4192 #endif
4193
4194 bool isBackgroundTaskMode = false;
4195 #ifdef MOZ_BACKGROUNDTASKS
4196 Maybe<nsCString> backgroundTasks = BackgroundTasks::GetBackgroundTasks();
4197 if (backgroundTasks.isSome()) {
4198 isBackgroundTaskMode = true;
4199 CrashReporter::AnnotateCrashReport(
4200 CrashReporter::Annotation::BackgroundTaskName, backgroundTasks.ref());
4201 }
4202 #endif
4203 CrashReporter::AnnotateCrashReport(
4204 CrashReporter::Annotation::BackgroundTaskMode, isBackgroundTaskMode);
4205
4206 CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::HeadlessMode,
4207 gfxPlatform::IsHeadless());
4208
4209 CrashReporter::SetRestartArgs(gArgc, gArgv);
4210
4211 // annotate other data (user id etc)
4212 nsCOMPtr<nsIFile> userAppDataDir;
4213 if (NS_SUCCEEDED(mDirProvider.GetUserAppDataDirectory(
4214 getter_AddRefs(userAppDataDir)))) {
4215 CrashReporter::SetupExtraData(userAppDataDir,
4216 nsDependentCString(mAppData->buildID));
4217
4218 // see if we have a crashreporter-override.ini in the application
4219 // directory
4220 nsCOMPtr<nsIFile> overrideini;
4221 if (NS_SUCCEEDED(
4222 mDirProvider.GetAppDir()->Clone(getter_AddRefs(overrideini))) &&
4223 NS_SUCCEEDED(
4224 overrideini->AppendNative("crashreporter-override.ini"_ns))) {
4225 #ifdef XP_WIN
4226 nsAutoString overridePathW;
4227 overrideini->GetPath(overridePathW);
4228 NS_ConvertUTF16toUTF8 overridePath(overridePathW);
4229 #else
4230 nsAutoCString overridePath;
4231 overrideini->GetNativePath(overridePath);
4232 #endif
4233
4234 SaveWordToEnv("MOZ_CRASHREPORTER_STRINGS_OVERRIDE", overridePath);
4235 }
4236 }
4237 }
4238
4239 #if defined(MOZ_SANDBOX) && defined(XP_WIN)
4240 if (mAppData->sandboxBrokerServices) {
4241 SandboxBroker::Initialize(mAppData->sandboxBrokerServices);
4242 } else {
4243 # if defined(MOZ_SANDBOX)
4244 // If we're sandboxing content and we fail to initialize, then crashing here
4245 // seems like the sensible option.
4246 if (BrowserTabsRemoteAutostart()) {
4247 MOZ_CRASH("Failed to initialize broker services, can't continue.");
4248 }
4249 # endif
4250 // Otherwise just warn for the moment, as most things will work.
4251 NS_WARNING(
4252 "Failed to initialize broker services, sandboxed processes will "
4253 "fail to start.");
4254 }
4255 if (mAppData->sandboxPermissionsService) {
4256 SandboxPermissions::Initialize(mAppData->sandboxPermissionsService,
4257 nullptr);
4258 }
4259 #endif
4260
4261 #ifdef XP_MACOSX
4262 // Set up ability to respond to system (Apple) events. This must occur before
4263 // ProcessUpdates to ensure that links clicked in external applications aren't
4264 // lost when updates are pending.
4265 SetupMacApplicationDelegate();
4266
4267 if (EnvHasValue("MOZ_LAUNCHED_CHILD")) {
4268 // This is needed, on relaunch, to force the OS to use the "Cocoa Dock
4269 // API". Otherwise the call to ReceiveNextEvent() below will make it
4270 // use the "Carbon Dock API". For more info see bmo bug 377166.
4271 EnsureUseCocoaDockAPI();
4272
4273 // When the app relaunches, the original process exits. This causes
4274 // the dock tile to stop bouncing, lose the "running" triangle, and
4275 // if the tile does not permanently reside in the Dock, even disappear.
4276 // This can be confusing to the user, who is expecting the app to launch.
4277 // Calling ReceiveNextEvent without requesting any event is enough to
4278 // cause a dock tile for the child process to appear.
4279 const EventTypeSpec kFakeEventList[] = {{INT_MAX, INT_MAX}};
4280 EventRef event;
4281 ::ReceiveNextEvent(GetEventTypeCount(kFakeEventList), kFakeEventList,
4282 kEventDurationNoWait, false, &event);
4283 }
4284
4285 if (CheckArg("foreground")) {
4286 // The original process communicates that it was in the foreground by
4287 // adding this argument. This new process, which is taking over for
4288 // the old one, should make itself the active application.
4289 ProcessSerialNumber psn;
4290 if (::GetCurrentProcess(&psn) == noErr) ::SetFrontProcess(&psn);
4291 }
4292 #endif
4293
4294 SaveToEnv("MOZ_LAUNCHED_CHILD=");
4295
4296 // On Windows, the -os-restarted command line switch lets us know when we are
4297 // restarted via RegisterApplicationRestart. May be used for other OSes later.
4298 if (CheckArg("os-restarted", nullptr, CheckArgFlag::RemoveArg) == ARG_FOUND) {
4299 gRestartedByOS = true;
4300 }
4301
4302 gRestartArgc = gArgc;
4303 gRestartArgv =
4304 (char**)malloc(sizeof(char*) * (gArgc + 1 + (override ? 2 : 0)));
4305 if (!gRestartArgv) {
4306 return 1;
4307 }
4308
4309 int i;
4310 for (i = 0; i < gArgc; ++i) {
4311 gRestartArgv[i] = gArgv[i];
4312 }
4313
4314 // Add the -override argument back (it is removed automatically be CheckArg)
4315 // if there is one
4316 if (override) {
4317 gRestartArgv[gRestartArgc++] = const_cast<char*>("-override");
4318 gRestartArgv[gRestartArgc++] = const_cast<char*>(override);
4319 }
4320
4321 gRestartArgv[gRestartArgc] = nullptr;
4322
4323 Maybe<bool> safeModeRequested = IsSafeModeRequested(gArgc, gArgv);
4324 if (!safeModeRequested) {
4325 return 1;
4326 }
4327 #ifdef MOZ_BACKGROUNDTASKS
4328 if (BackgroundTasks::IsBackgroundTaskMode()) {
4329 safeModeRequested = Some(false);
4330
4331 // Remove the --backgroundtask arg now that it has been saved in
4332 // gRestartArgv.
4333 const char* tmpBackgroundTaskName = nullptr;
4334 Unused << CheckArg("backgroundtask", &tmpBackgroundTaskName,
4335 CheckArgFlag::RemoveArg);
4336 }
4337 #endif
4338
4339 gSafeMode = safeModeRequested.value();
4340
4341 #ifdef XP_WIN
4342 {
4343 // Add CPU microcode version to the crash report as "CPUMicrocodeVersion".
4344 // It feels like this code may belong in nsSystemInfo instead.
4345 int cpuUpdateRevision = -1;
4346 HKEY key;
4347 static const WCHAR keyName[] =
4348 L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0";
4349
4350 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, keyName, 0, KEY_QUERY_VALUE, &key) ==
4351 ERROR_SUCCESS) {
4352 DWORD updateRevision[2];
4353 DWORD len = sizeof(updateRevision);
4354 DWORD vtype;
4355
4356 // Windows 7 uses "Update Signature", 8 uses "Update Revision".
4357 // For AMD CPUs, "CurrentPatchLevel" is sometimes used.
4358 // Take the first one we find.
4359 LPCWSTR choices[] = {L"Update Signature", L"Update Revision",
4360 L"CurrentPatchLevel"};
4361 for (size_t oneChoice = 0; oneChoice < ArrayLength(choices);
4362 oneChoice++) {
4363 if (RegQueryValueExW(key, choices[oneChoice], 0, &vtype,
4364 reinterpret_cast<LPBYTE>(updateRevision),
4365 &len) == ERROR_SUCCESS) {
4366 if (vtype == REG_BINARY && len == sizeof(updateRevision)) {
4367 // The first word is unused
4368 cpuUpdateRevision = static_cast<int>(updateRevision[1]);
4369 break;
4370 } else if (vtype == REG_DWORD && len == sizeof(updateRevision[0])) {
4371 cpuUpdateRevision = static_cast<int>(updateRevision[0]);
4372 break;
4373 }
4374 }
4375 }
4376 }
4377
4378 if (cpuUpdateRevision > 0) {
4379 CrashReporter::AnnotateCrashReport(
4380 CrashReporter::Annotation::CPUMicrocodeVersion,
4381 nsPrintfCString("0x%x", cpuUpdateRevision));
4382 }
4383 }
4384 #endif
4385
4386 CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::SafeMode,
4387 gSafeMode);
4388
4389 #if defined(MOZ_HAS_REMOTE)
4390 // Handle --no-remote and --new-instance command line arguments. Setup
4391 // the environment to better accommodate other components and various
4392 // restart scenarios.
4393 ar = CheckArg("no-remote");
4394 if (ar == ARG_FOUND || EnvHasValue("MOZ_NO_REMOTE")) {
4395 mDisableRemoteClient = true;
4396 mDisableRemoteServer = true;
4397 if (!EnvHasValue("MOZ_NO_REMOTE")) {
4398 SaveToEnv("MOZ_NO_REMOTE=1");
4399 }
4400 }
4401
4402 ar = CheckArg("new-instance");
4403 if (ar == ARG_FOUND || EnvHasValue("MOZ_NEW_INSTANCE")) {
4404 mDisableRemoteClient = true;
4405 }
4406 #else
4407 // These arguments do nothing in platforms with no remoting support but we
4408 // should remove them from the command line anyway.
4409 CheckArg("no-remote");
4410 CheckArg("new-instance");
4411 #endif
4412
4413 ar = CheckArg("offline");
4414 if (ar || EnvHasValue("XRE_START_OFFLINE")) {
4415 mStartOffline = true;
4416 }
4417
4418 // Handle --help, --full-version and --version command line arguments.
4419 // They should return quickly, so we deal with them here.
4420 if (CheckArg("h") || CheckArg("help") || CheckArg("?")) {
4421 DumpHelp();
4422 *aExitFlag = true;
4423 return 0;
4424 }
4425
4426 if (CheckArg("v") || CheckArg("version")) {
4427 DumpVersion();
4428 *aExitFlag = true;
4429 return 0;
4430 }
4431
4432 if (CheckArg("full-version")) {
4433 DumpFullVersion();
4434 *aExitFlag = true;
4435 return 0;
4436 }
4437
4438 rv = XRE_InitCommandLine(gArgc, gArgv);
4439 NS_ENSURE_SUCCESS(rv, 1);
4440
4441 return 0;
4442 }
4443
4444 #if defined(XP_LINUX) && !defined(ANDROID)
4445
AnnotateLSBRelease(void *)4446 static void AnnotateLSBRelease(void*) {
4447 nsCString dist, desc, release, codename;
4448 if (widget::lsb::GetLSBRelease(dist, desc, release, codename)) {
4449 CrashReporter::AppendAppNotesToCrashReport(desc);
4450 }
4451 }
4452
4453 #endif // defined(XP_LINUX) && !defined(ANDROID)
4454
4455 #ifdef XP_WIN
ReadAheadSystemDll(const wchar_t * dllName)4456 static void ReadAheadSystemDll(const wchar_t* dllName) {
4457 wchar_t dllPath[MAX_PATH];
4458 if (ConstructSystem32Path(dllName, dllPath, MAX_PATH)) {
4459 ReadAheadLib(dllPath);
4460 }
4461 }
4462
ReadAheadPackagedDll(const wchar_t * dllName,const wchar_t * aGREDir)4463 static void ReadAheadPackagedDll(const wchar_t* dllName,
4464 const wchar_t* aGREDir) {
4465 wchar_t dllPath[MAX_PATH];
4466 swprintf(dllPath, MAX_PATH, L"%s\\%s", aGREDir, dllName);
4467 ReadAheadLib(dllPath);
4468 }
4469
ReadAheadDlls_ThreadStart(void * arg)4470 static void PR_CALLBACK ReadAheadDlls_ThreadStart(void* arg) {
4471 UniquePtr<wchar_t[]> greDir(static_cast<wchar_t*>(arg));
4472
4473 // In Bug 1628903, we investigated which DLLs we should prefetch in
4474 // order to reduce disk I/O and improve startup on Windows machines.
4475 // Our ultimate goal is to measure the impact of these improvements on
4476 // retention (see Bug 1640087). Before we place this within a pref,
4477 // we should ensure this feature only ships to the nightly channel
4478 // and monitor results from that subset.
4479 if (greDir) {
4480 // Prefetch the DLLs shipped with firefox
4481 ReadAheadPackagedDll(L"libegl.dll", greDir.get());
4482 ReadAheadPackagedDll(L"libGLESv2.dll", greDir.get());
4483 ReadAheadPackagedDll(L"nssckbi.dll", greDir.get());
4484 ReadAheadPackagedDll(L"freebl3.dll", greDir.get());
4485 ReadAheadPackagedDll(L"softokn3.dll", greDir.get());
4486
4487 // Prefetch the system DLLs
4488 ReadAheadSystemDll(L"DWrite.dll");
4489 ReadAheadSystemDll(L"D3DCompiler_47.dll");
4490 } else {
4491 // Load DataExchange.dll and twinapi.appcore.dll for
4492 // nsWindow::EnableDragDrop
4493 ReadAheadSystemDll(L"DataExchange.dll");
4494 ReadAheadSystemDll(L"twinapi.appcore.dll");
4495
4496 // Load twinapi.dll for WindowsUIUtils::UpdateTabletModeState
4497 ReadAheadSystemDll(L"twinapi.dll");
4498
4499 // Load explorerframe.dll for WinTaskbar::Initialize
4500 ReadAheadSystemDll(L"ExplorerFrame.dll");
4501
4502 // Load WinTypes.dll for nsOSHelperAppService::GetApplicationDescription
4503 ReadAheadSystemDll(L"WinTypes.dll");
4504 }
4505 }
4506 #endif
4507
4508 #if defined(MOZ_WAYLAND)
IsWaylandEnabled()4509 bool IsWaylandEnabled() {
4510 const char* waylandDisplay = PR_GetEnv("WAYLAND_DISPLAY");
4511 if (!waylandDisplay) {
4512 return false;
4513 }
4514 if (!PR_GetEnv("DISPLAY")) {
4515 // No X11 display, so try to run wayland.
4516 return true;
4517 }
4518 // MOZ_ENABLE_WAYLAND is our primary Wayland on/off switch.
4519 if (const char* waylandPref = PR_GetEnv("MOZ_ENABLE_WAYLAND")) {
4520 return *waylandPref == '1';
4521 }
4522 if (const char* backendPref = PR_GetEnv("GDK_BACKEND")) {
4523 if (!strncmp(backendPref, "wayland", 7)) {
4524 NS_WARNING(
4525 "Wayland backend should be enabled by MOZ_ENABLE_WAYLAND=1."
4526 "GDK_BACKEND is a Gtk3 debug variable and may cause issues.");
4527 return true;
4528 }
4529 }
4530 # ifdef EARLY_BETA_OR_EARLIER
4531 // Enable by default when we're running on a recent enough GTK version. We'd
4532 // like to check further details like compositor version and so on ideally
4533 // to make sure we don't enable it on old Mutter or what not, but we can't,
4534 // so let's assume that if the user is running on a Wayland session by
4535 // default we're ok, since either the distro has enabled Wayland by default,
4536 // or the user has gone out of their way to use Wayland.
4537 //
4538 // TODO(emilio): If users hit problems, we might be able to restrict it to
4539 // GNOME / KDE / known-good-desktop environments by checking
4540 // XDG_CURRENT_DESKTOP or so...
4541 return !gtk_check_version(3, 24, 30);
4542 # else
4543 return false;
4544 # endif
4545 }
4546 #endif
4547
4548 #if defined(MOZ_UPDATER) && !defined(MOZ_WIDGET_ANDROID)
4549 enum struct ShouldNotProcessUpdatesReason {
4550 DevToolsLaunching,
4551 NotAnUpdatingTask,
4552 OtherInstanceRunning,
4553 };
4554
ShouldNotProcessUpdatesReasonAsString(ShouldNotProcessUpdatesReason aReason)4555 const char* ShouldNotProcessUpdatesReasonAsString(
4556 ShouldNotProcessUpdatesReason aReason) {
4557 switch (aReason) {
4558 case ShouldNotProcessUpdatesReason::DevToolsLaunching:
4559 return "DevToolsLaunching";
4560 case ShouldNotProcessUpdatesReason::NotAnUpdatingTask:
4561 return "NotAnUpdatingTask";
4562 case ShouldNotProcessUpdatesReason::OtherInstanceRunning:
4563 return "OtherInstanceRunning";
4564 default:
4565 MOZ_CRASH("impossible value for ShouldNotProcessUpdatesReason");
4566 }
4567 }
4568
ShouldNotProcessUpdates(nsXREDirProvider & aDirProvider)4569 Maybe<ShouldNotProcessUpdatesReason> ShouldNotProcessUpdates(
4570 nsXREDirProvider& aDirProvider) {
4571 // Do not process updates if we're launching devtools, as evidenced by
4572 // "--chrome ..." with the browser toolbox chrome document URL.
4573
4574 // Keep this synchronized with the value of the same name in
4575 // devtools/client/framework/browser-toolbox/Launcher.jsm. Or, for bonus
4576 // points, lift this value to nsIXulRuntime or similar, so that it can be
4577 // accessed in both locations. (The prefs service isn't available at this
4578 // point so the simplest manner of sharing the value is not available to us.)
4579 const char* BROWSER_TOOLBOX_WINDOW_URL =
4580 "chrome://devtools/content/framework/browser-toolbox/window.html";
4581
4582 const char* chromeParam = nullptr;
4583 if (ARG_FOUND == CheckArg("chrome", &chromeParam, CheckArgFlag::None)) {
4584 if (!chromeParam || !strcmp(BROWSER_TOOLBOX_WINDOW_URL, chromeParam)) {
4585 NS_WARNING("ShouldNotProcessUpdates(): DevToolsLaunching");
4586 return Some(ShouldNotProcessUpdatesReason::DevToolsLaunching);
4587 }
4588 }
4589
4590 # ifdef MOZ_BACKGROUNDTASKS
4591 // Do not process updates if we're running a background task mode and another
4592 // instance is already running. This avoids periodic maintenance updating
4593 // underneath a browsing session.
4594 Maybe<nsCString> backgroundTasks = BackgroundTasks::GetBackgroundTasks();
4595 if (backgroundTasks.isSome()) {
4596 // Only process updates for specific tasks: at this time, the
4597 // `backgroundupdate` task and the test-only `shouldprocessupdates` task.
4598 //
4599 // Background tasks can be sparked by Firefox instances that are shutting
4600 // down, which can cause races between the task startup trying to update and
4601 // Firefox trying to invoke the updater. This happened when converting
4602 // `pingsender` to a background task, since it is launched to send pings at
4603 // shutdown: Bug 1736373.
4604 //
4605 // We'd prefer to have this be a property of the task definition sibling to
4606 // `backgroundTaskTimeoutSec`, but when we reach this code we're well before
4607 // we can load the task JSM.
4608 if (!BackgroundTasks::IsUpdatingTaskName(backgroundTasks.ref())) {
4609 NS_WARNING("ShouldNotProcessUpdates(): NotAnUpdatingTask");
4610 return Some(ShouldNotProcessUpdatesReason::NotAnUpdatingTask);
4611 }
4612
4613 // At this point we have a dir provider but no XPCOM directory service. We
4614 // launch the update sync manager using that information so that it doesn't
4615 // need to ask for (and fail to find) the directory service.
4616 nsCOMPtr<nsIFile> anAppFile;
4617 bool persistent;
4618 nsresult rv = aDirProvider.GetFile(XRE_EXECUTABLE_FILE, &persistent,
4619 getter_AddRefs(anAppFile));
4620 if (NS_FAILED(rv) || !anAppFile) {
4621 // Strange, but not a reason to skip processing updates.
4622 return Nothing();
4623 }
4624
4625 auto updateSyncManager = new nsUpdateSyncManager(anAppFile);
4626
4627 bool otherInstance = false;
4628 updateSyncManager->IsOtherInstanceRunning(&otherInstance);
4629 if (otherInstance) {
4630 NS_WARNING("ShouldNotProcessUpdates(): OtherInstanceRunning");
4631 return Some(ShouldNotProcessUpdatesReason::OtherInstanceRunning);
4632 }
4633 }
4634 # endif
4635
4636 return Nothing();
4637 }
4638 #endif
4639
4640 namespace mozilla::startup {
GetIncompleteStartupFile(nsIFile * aProfLD)4641 Result<nsCOMPtr<nsIFile>, nsresult> GetIncompleteStartupFile(nsIFile* aProfLD) {
4642 nsCOMPtr<nsIFile> crashFile;
4643 MOZ_TRY(aProfLD->Clone(getter_AddRefs(crashFile)));
4644 MOZ_TRY(crashFile->Append(FILE_STARTUP_INCOMPLETE));
4645 return std::move(crashFile);
4646 }
4647 } // namespace mozilla::startup
4648
4649 // Check whether the last startup attempt resulted in a crash within the
4650 // last 6 hours.
4651 // Note that this duplicates the logic in nsAppStartup::TrackStartupCrashBegin,
4652 // which runs too late for our purposes.
CheckLastStartupWasCrash()4653 Result<bool, nsresult> XREMain::CheckLastStartupWasCrash() {
4654 constexpr int32_t MAX_TIME_SINCE_STARTUP = 6 * 60 * 60 * 1000;
4655
4656 nsCOMPtr<nsIFile> crashFile;
4657 MOZ_TRY_VAR(crashFile, GetIncompleteStartupFile(mProfLD));
4658
4659 // Attempt to create the incomplete startup canary file. If the file already
4660 // exists, this fails, and we know the last startup was a success. If it
4661 // doesn't already exist, it is created, and will be removed at the end of
4662 // the startup crash detection window.
4663 AutoFDClose fd;
4664 Unused << crashFile->OpenNSPRFileDesc(PR_WRONLY | PR_CREATE_FILE | PR_EXCL,
4665 0666, &fd.rwget());
4666 if (fd) {
4667 return false;
4668 }
4669
4670 PRTime lastModifiedTime;
4671 MOZ_TRY(crashFile->GetLastModifiedTime(&lastModifiedTime));
4672
4673 // If the file exists, and was created within the appropriate time window,
4674 // the last startup was recent and resulted in a crash.
4675 PRTime now = PR_Now() / PR_USEC_PER_MSEC;
4676 return now - lastModifiedTime <= MAX_TIME_SINCE_STARTUP;
4677 }
4678
4679 /*
4680 * XRE_mainStartup - Initializes the profile and various other services.
4681 * Main() will exit early if either return value != 0 or if aExitFlag is
4682 * true.
4683 */
XRE_mainStartup(bool * aExitFlag)4684 int XREMain::XRE_mainStartup(bool* aExitFlag) {
4685 nsresult rv;
4686
4687 if (!aExitFlag) return 1;
4688 *aExitFlag = false;
4689
4690 #ifdef XP_MACOSX
4691 mozilla::MacAutoreleasePool pool;
4692 #endif
4693
4694 // Enable Telemetry IO Reporting on DEBUG, nightly and local builds,
4695 // but disable it on FUZZING builds and for ANDROID.
4696 #ifndef FUZZING
4697 # ifndef ANDROID
4698 # ifdef DEBUG
4699 mozilla::Telemetry::InitIOReporting(gAppData->xreDirectory);
4700 # else
4701 {
4702 const char* releaseChannel = MOZ_STRINGIFY(MOZ_UPDATE_CHANNEL);
4703 if (strcmp(releaseChannel, "nightly") == 0 ||
4704 strcmp(releaseChannel, "default") == 0) {
4705 mozilla::Telemetry::InitIOReporting(gAppData->xreDirectory);
4706 }
4707 }
4708 # endif /* DEBUG */
4709 # endif /* ANDROID */
4710 #endif /* FUZZING */
4711
4712 #if defined(XP_WIN)
4713 // Enable the HeapEnableTerminationOnCorruption exploit mitigation. We ignore
4714 // the return code because it always returns success, although it has no
4715 // effect on Windows older than XP SP3.
4716 HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);
4717 #endif /* XP_WIN */
4718
4719 #if defined(MOZ_WIDGET_GTK)
4720 // Stash DESKTOP_STARTUP_ID in malloc'ed memory because gtk_init will clear
4721 // it.
4722 # define HAVE_DESKTOP_STARTUP_ID
4723 const char* desktopStartupIDEnv = PR_GetEnv("DESKTOP_STARTUP_ID");
4724 if (desktopStartupIDEnv) {
4725 mDesktopStartupID.Assign(desktopStartupIDEnv);
4726 }
4727 #endif
4728
4729 #if defined(XP_WIN)
4730 {
4731 // Save the shortcut path before lpTitle is replaced by an AUMID,
4732 // such as by WinTaskbar
4733 STARTUPINFOW si;
4734 GetStartupInfoW(&si);
4735 if (si.dwFlags & STARTF_TITLEISAPPID) {
4736 NS_WARNING("AUMID was already set, shortcut may have been lost.");
4737 } else if ((si.dwFlags & STARTF_TITLEISLINKNAME) && si.lpTitle) {
4738 gProcessStartupShortcut.Assign(si.lpTitle);
4739 }
4740 }
4741 #endif /* XP_WIN */
4742
4743 #if defined(MOZ_WIDGET_GTK)
4744 // setup for private colormap. Ideally we'd like to do this
4745 // in nsAppShell::Create, but we need to get in before gtk
4746 // has been initialized to make sure everything is running
4747 // consistently.
4748
4749 // Set program name to the one defined in application.ini.
4750 g_set_prgname(gAppData->remotingName);
4751
4752 // Initialize GTK here for splash.
4753
4754 # if defined(MOZ_WIDGET_GTK) && defined(MOZ_X11)
4755 // Disable XInput2 multidevice support due to focus bugginess.
4756 // See bugs 1182700, 1170342.
4757 // gdk_disable_multidevice() affects Gdk X11 backend only,
4758 // the multidevice support is always enabled on Wayland backend.
4759 const char* useXI2 = PR_GetEnv("MOZ_USE_XINPUT2");
4760 if (!useXI2 || (*useXI2 == '0')) gdk_disable_multidevice();
4761 # endif
4762
4763 // Open the display ourselves instead of using gtk_init, so that we can
4764 // close it without fear that one day gtk might clean up the display it
4765 // opens.
4766 if (!gtk_parse_args(&gArgc, &gArgv)) return 1;
4767 #endif /* MOZ_WIDGET_GTK */
4768
4769 #ifdef FUZZING
4770 if (PR_GetEnv("FUZZER")) {
4771 *aExitFlag = true;
4772 return mozilla::fuzzerRunner->Run(&gArgc, &gArgv);
4773 }
4774 #endif
4775
4776 if (PR_GetEnv("MOZ_RUN_GTEST")) {
4777 int result;
4778 #ifdef XP_WIN
4779 UseParentConsole();
4780 #endif
4781 // RunGTest will only be set if we're in xul-unit
4782 if (mozilla::RunGTest) {
4783 gIsGtest = true;
4784 result = mozilla::RunGTest(&gArgc, gArgv);
4785 gIsGtest = false;
4786 } else {
4787 result = 1;
4788 printf("TEST-UNEXPECTED-FAIL | gtest | Not compiled with enable-tests\n");
4789 }
4790 *aExitFlag = true;
4791 return result;
4792 }
4793
4794 #ifdef MOZ_HAS_REMOTE
4795 if (gfxPlatform::IsHeadless()) {
4796 mDisableRemoteClient = true;
4797 mDisableRemoteServer = true;
4798 }
4799 #endif
4800
4801 #ifdef MOZ_X11
4802 // Init X11 in thread-safe mode. Must be called prior to the first call to
4803 // XOpenDisplay (called inside gdk_display_open). This is a requirement for
4804 // off main tread compositing.
4805 if (!gfxPlatform::IsHeadless()) {
4806 XInitThreads();
4807 }
4808 #endif
4809 #if defined(MOZ_WIDGET_GTK)
4810 if (!gfxPlatform::IsHeadless()) {
4811 const char* display_name = nullptr;
4812 bool saveDisplayArg = false;
4813
4814 // display_name is owned by gdk.
4815 display_name = gdk_get_display_arg_name();
4816 // if --display argument is given make sure it's
4817 // also passed to ContentChild::Init() by MOZ_GDK_DISPLAY.
4818 if (display_name) {
4819 SaveWordToEnv("MOZ_GDK_DISPLAY", nsDependentCString(display_name));
4820 saveDisplayArg = true;
4821 }
4822
4823 bool waylandEnabled = false;
4824 # if defined(MOZ_WAYLAND)
4825 waylandEnabled = IsWaylandEnabled();
4826 # endif
4827 // On Wayland disabled builds read X11 DISPLAY env exclusively
4828 // and don't care about different displays.
4829 if (!waylandEnabled && !display_name) {
4830 display_name = PR_GetEnv("DISPLAY");
4831 if (!display_name) {
4832 PR_fprintf(PR_STDERR,
4833 "Error: no DISPLAY environment variable specified\n");
4834 return 1;
4835 }
4836 }
4837
4838 if (display_name) {
4839 mGdkDisplay = gdk_display_open(display_name);
4840 if (!mGdkDisplay) {
4841 PR_fprintf(PR_STDERR, "Error: cannot open display: %s\n", display_name);
4842 return 1;
4843 }
4844 if (saveDisplayArg) {
4845 if (GdkIsX11Display(mGdkDisplay)) {
4846 SaveWordToEnv("DISPLAY", nsDependentCString(display_name));
4847 }
4848 # ifdef MOZ_WAYLAND
4849 else if (GdkIsWaylandDisplay(mGdkDisplay)) {
4850 SaveWordToEnv("WAYLAND_DISPLAY", nsDependentCString(display_name));
4851 }
4852 # endif
4853 }
4854 }
4855 # ifdef MOZ_WIDGET_GTK
4856 else {
4857 mGdkDisplay =
4858 gdk_display_manager_open_display(gdk_display_manager_get(), nullptr);
4859 }
4860 # endif
4861 }
4862 #endif
4863 #if defined(MOZ_HAS_REMOTE)
4864 // handle --remote now that xpcom is fired up
4865 mRemoteService = new nsRemoteService(gAppData->remotingName);
4866 if (mRemoteService && !mDisableRemoteServer) {
4867 mRemoteService->LockStartup();
4868 gRemoteService = mRemoteService;
4869 }
4870 #endif
4871 #if defined(MOZ_WIDGET_GTK)
4872 g_set_application_name(mAppData->name);
4873
4874 #endif /* defined(MOZ_WIDGET_GTK) */
4875 #ifdef MOZ_X11
4876 // Do this after initializing GDK, or GDK will install its own handler.
4877 XRE_InstallX11ErrorHandler();
4878 #endif
4879
4880 // Call the code to install our handler
4881 #ifdef MOZ_JPROF
4882 setupProfilingStuff();
4883 #endif
4884
4885 rv = NS_CreateNativeAppSupport(getter_AddRefs(mNativeApp));
4886 if (NS_FAILED(rv)) return 1;
4887
4888 bool canRun = false;
4889 rv = mNativeApp->Start(&canRun);
4890 if (NS_FAILED(rv) || !canRun) {
4891 return 1;
4892 }
4893
4894 #if defined(HAVE_DESKTOP_STARTUP_ID) && defined(MOZ_WIDGET_GTK)
4895 // DESKTOP_STARTUP_ID is cleared now,
4896 // we recover it in case we need a restart.
4897 if (!mDesktopStartupID.IsEmpty()) {
4898 nsAutoCString desktopStartupEnv;
4899 desktopStartupEnv.AssignLiteral("DESKTOP_STARTUP_ID=");
4900 desktopStartupEnv.Append(mDesktopStartupID);
4901 // Leak it with extreme prejudice!
4902 PR_SetEnv(ToNewCString(desktopStartupEnv));
4903 }
4904 #endif
4905
4906 // Support exiting early for testing startup sequence. Bug 1360493
4907 if (CheckArg("test-launch-without-hang")) {
4908 *aExitFlag = true;
4909 return 0;
4910 }
4911
4912 #ifdef MOZ_BACKGROUNDTASKS
4913 if (BackgroundTasks::IsBackgroundTaskMode()) {
4914 // Allow tests to specify profile path via the environment.
4915 if (!EnvHasValue("XRE_PROFILE_PATH")) {
4916 nsString installHash;
4917 mDirProvider.GetInstallHash(installHash);
4918
4919 nsCOMPtr<nsIFile> file;
4920 nsresult rv = BackgroundTasks::CreateTemporaryProfileDirectory(
4921 NS_LossyConvertUTF16toASCII(installHash), getter_AddRefs(file));
4922 if (NS_WARN_IF(NS_FAILED(rv))) {
4923 return 1;
4924 }
4925
4926 SaveFileToEnv("XRE_PROFILE_PATH", file);
4927 }
4928 }
4929 #endif
4930
4931 rv = NS_NewToolkitProfileService(getter_AddRefs(mProfileSvc));
4932 if (rv == NS_ERROR_FILE_ACCESS_DENIED) {
4933 PR_fprintf(PR_STDERR,
4934 "Error: Access was denied while trying to open files in "
4935 "your profile directory.\n");
4936 }
4937 if (NS_FAILED(rv)) {
4938 // We failed to choose or create profile - notify user and quit
4939 ProfileMissingDialog(mNativeApp);
4940 return 1;
4941 }
4942
4943 bool wasDefaultSelection;
4944 nsCOMPtr<nsIToolkitProfile> profile;
4945 rv = SelectProfile(mProfileSvc, mNativeApp, getter_AddRefs(mProfD),
4946 getter_AddRefs(mProfLD), getter_AddRefs(profile),
4947 &wasDefaultSelection);
4948 if (rv == NS_ERROR_LAUNCHED_CHILD_PROCESS || rv == NS_ERROR_ABORT) {
4949 *aExitFlag = true;
4950 return 0;
4951 }
4952
4953 if (NS_FAILED(rv)) {
4954 // We failed to choose or create profile - notify user and quit
4955 ProfileMissingDialog(mNativeApp);
4956 return 1;
4957 }
4958
4959 #if defined(MOZ_HAS_REMOTE)
4960 if (mRemoteService) {
4961 // We want a unique profile name to identify the remote instance.
4962 nsCString profileName;
4963 if (profile) {
4964 rv = profile->GetName(profileName);
4965 }
4966 if (!profile || NS_FAILED(rv) || profileName.IsEmpty()) {
4967 // Couldn't get a name from the profile. Use the directory name?
4968 nsString leafName;
4969 rv = mProfD->GetLeafName(leafName);
4970 if (NS_SUCCEEDED(rv)) {
4971 CopyUTF16toUTF8(leafName, profileName);
4972 }
4973 }
4974
4975 mRemoteService->SetProfile(profileName);
4976
4977 if (!mDisableRemoteClient) {
4978 // Try to remote the entire command line. If this fails, start up
4979 // normally.
4980 const char* desktopStartupIDPtr =
4981 mDesktopStartupID.IsEmpty() ? nullptr : mDesktopStartupID.get();
4982
4983 RemoteResult rr = mRemoteService->StartClient(desktopStartupIDPtr);
4984 if (rr == REMOTE_FOUND) {
4985 *aExitFlag = true;
4986 mRemoteService->UnlockStartup();
4987 return 0;
4988 }
4989 if (rr == REMOTE_ARG_BAD) {
4990 mRemoteService->UnlockStartup();
4991 return 1;
4992 }
4993 }
4994 }
4995 #endif
4996
4997 #if defined(MOZ_UPDATER) && !defined(MOZ_WIDGET_ANDROID)
4998 Maybe<ShouldNotProcessUpdatesReason> shouldNotProcessUpdatesReason =
4999 ShouldNotProcessUpdates(mDirProvider);
5000 if (shouldNotProcessUpdatesReason.isNothing()) {
5001 // Check for and process any available updates
5002 nsCOMPtr<nsIFile> updRoot;
5003 bool persistent;
5004 rv = mDirProvider.GetFile(XRE_UPDATE_ROOT_DIR, &persistent,
5005 getter_AddRefs(updRoot));
5006 // XRE_UPDATE_ROOT_DIR may fail. Fallback to appDir if failed
5007 if (NS_FAILED(rv)) {
5008 updRoot = mDirProvider.GetAppDir();
5009 }
5010
5011 // If the MOZ_TEST_PROCESS_UPDATES environment variable already exists, then
5012 // we are being called from the callback application.
5013 if (EnvHasValue("MOZ_TEST_PROCESS_UPDATES")) {
5014 // If the caller has asked us to log our arguments, do so. This is used
5015 // to make sure that the maintenance service successfully launches the
5016 // callback application.
5017 const char* logFile = nullptr;
5018 if (ARG_FOUND == CheckArg("dump-args", &logFile)) {
5019 FILE* logFP = fopen(logFile, "wb");
5020 if (logFP) {
5021 for (int i = 1; i < gRestartArgc; ++i) {
5022 fprintf(logFP, "%s\n", gRestartArgv[i]);
5023 }
5024 fclose(logFP);
5025 }
5026 }
5027 *aExitFlag = true;
5028 return 0;
5029 }
5030
5031 // Support for processing an update and exiting. The
5032 // MOZ_TEST_PROCESS_UPDATES environment variable will be part of the
5033 // updater's environment and the application that is relaunched by the
5034 // updater. When the application is relaunched by the updater it will be
5035 // removed below and the application will exit.
5036 if (CheckArg("test-process-updates")) {
5037 SaveToEnv("MOZ_TEST_PROCESS_UPDATES=1");
5038 }
5039 nsCOMPtr<nsIFile> exeFile, exeDir;
5040 rv = mDirProvider.GetFile(XRE_EXECUTABLE_FILE, &persistent,
5041 getter_AddRefs(exeFile));
5042 NS_ENSURE_SUCCESS(rv, 1);
5043 rv = exeFile->GetParent(getter_AddRefs(exeDir));
5044 NS_ENSURE_SUCCESS(rv, 1);
5045 ProcessUpdates(mDirProvider.GetGREDir(), exeDir, updRoot, gRestartArgc,
5046 gRestartArgv, mAppData->version);
5047 if (EnvHasValue("MOZ_TEST_PROCESS_UPDATES")) {
5048 SaveToEnv("MOZ_TEST_PROCESS_UPDATES=");
5049 *aExitFlag = true;
5050 return 0;
5051 }
5052 } else {
5053 if (CheckArg("test-process-updates") ||
5054 EnvHasValue("MOZ_TEST_PROCESS_UPDATES")) {
5055 // Support for testing *not* processing an update. The launched process
5056 // can witness this environment variable and conclude that its runtime
5057 // environment resulted in not processing updates.
5058
5059 SaveToEnv(nsPrintfCString(
5060 "MOZ_TEST_PROCESS_UPDATES=ShouldNotProcessUpdates(): %s",
5061 ShouldNotProcessUpdatesReasonAsString(
5062 shouldNotProcessUpdatesReason.value()))
5063 .get());
5064 }
5065 }
5066 #endif
5067
5068 // We now know there is no existing instance using the selected profile. If
5069 // the profile wasn't selected by specific command line arguments and the
5070 // user has chosen to show the profile manager on startup then do that.
5071 if (wasDefaultSelection) {
5072 bool useSelectedProfile;
5073 rv = mProfileSvc->GetStartWithLastProfile(&useSelectedProfile);
5074 NS_ENSURE_SUCCESS(rv, 1);
5075
5076 if (!useSelectedProfile) {
5077 rv = ShowProfileManager(mProfileSvc, mNativeApp);
5078 if (rv == NS_ERROR_LAUNCHED_CHILD_PROCESS || rv == NS_ERROR_ABORT) {
5079 *aExitFlag = true;
5080 return 0;
5081 }
5082 if (NS_FAILED(rv)) {
5083 return 1;
5084 }
5085 }
5086 }
5087
5088 // We always want to lock the profile even if we're actually going to reset
5089 // it later.
5090 rv = LockProfile(mNativeApp, mProfD, mProfLD, profile,
5091 getter_AddRefs(mProfileLock));
5092 if (rv == NS_ERROR_LAUNCHED_CHILD_PROCESS || rv == NS_ERROR_ABORT) {
5093 *aExitFlag = true;
5094 return 0;
5095 } else if (NS_FAILED(rv)) {
5096 return 1;
5097 }
5098
5099 if (gDoProfileReset) {
5100 // Unlock the source profile.
5101 mProfileLock->Unlock();
5102
5103 // If we're resetting a profile, create a new one and use it to startup.
5104 gResetOldProfile = profile;
5105 rv = mProfileSvc->CreateResetProfile(getter_AddRefs(profile));
5106 if (NS_SUCCEEDED(rv)) {
5107 rv = profile->GetRootDir(getter_AddRefs(mProfD));
5108 NS_ENSURE_SUCCESS(rv, 1);
5109 SaveFileToEnv("XRE_PROFILE_PATH", mProfD);
5110
5111 rv = profile->GetLocalDir(getter_AddRefs(mProfLD));
5112 NS_ENSURE_SUCCESS(rv, 1);
5113 SaveFileToEnv("XRE_PROFILE_LOCAL_PATH", mProfLD);
5114
5115 // Lock the new profile
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;
5123 }
5124 } else {
5125 NS_WARNING("Profile reset failed.");
5126 return 1;
5127 }
5128 }
5129
5130 gProfileLock = mProfileLock;
5131
5132 nsAutoCString version;
5133 BuildVersion(version);
5134
5135 #ifdef TARGET_OS_ABI
5136 constexpr auto osABI = nsLiteralCString{TARGET_OS_ABI};
5137 #else
5138 // No TARGET_XPCOM_ABI, but at least the OS is known
5139 constexpr auto osABI = nsLiteralCString{OS_TARGET "_UNKNOWN"};
5140 #endif
5141
5142 // Check for version compatibility with the last version of the app this
5143 // profile was started with. The format of the version stamp is defined
5144 // by the BuildVersion function.
5145 // Also check to see if something has happened to invalidate our
5146 // fastload caches, like an app upgrade.
5147
5148 // If we see .purgecaches, that means someone did a make.
5149 // Re-register components to catch potential changes.
5150 nsCOMPtr<nsIFile> flagFile;
5151 if (mAppData->directory) {
5152 Unused << mAppData->directory->Clone(getter_AddRefs(flagFile));
5153 }
5154 if (flagFile) {
5155 flagFile->AppendNative(FILE_INVALIDATE_CACHES);
5156 }
5157
5158 bool cachesOK;
5159 bool isDowngrade;
5160 nsCString lastVersion;
5161 bool versionOK = CheckCompatibility(
5162 mProfD, version, osABI, mDirProvider.GetGREDir(), mAppData->directory,
5163 flagFile, &cachesOK, &isDowngrade, lastVersion);
5164
5165 MOZ_RELEASE_ASSERT(!cachesOK || lastVersion.Equals(version),
5166 "Caches cannot be good if the version has changed.");
5167
5168 #ifdef MOZ_BLOCK_PROFILE_DOWNGRADE
5169 // The argument check must come first so the argument is always removed from
5170 // the command line regardless of whether this is a downgrade or not.
5171 if (!CheckArg("allow-downgrade") && isDowngrade &&
5172 !EnvHasValue("MOZ_ALLOW_DOWNGRADE")) {
5173 rv = CheckDowngrade(mProfD, mNativeApp, mProfileSvc, lastVersion);
5174 if (rv == NS_ERROR_LAUNCHED_CHILD_PROCESS || rv == NS_ERROR_ABORT) {
5175 *aExitFlag = true;
5176 return 0;
5177 }
5178 }
5179 #endif
5180
5181 rv = mDirProvider.SetProfile(mProfD, mProfLD);
5182 NS_ENSURE_SUCCESS(rv, 1);
5183
5184 //////////////////////// NOW WE HAVE A PROFILE ////////////////////////
5185
5186 mozilla::Telemetry::SetProfileDir(mProfD);
5187
5188 if (mAppData->flags & NS_XRE_ENABLE_CRASH_REPORTER) {
5189 MakeOrSetMinidumpPath(mProfD);
5190 }
5191
5192 CrashReporter::SetProfileDirectory(mProfD);
5193
5194 #ifdef MOZ_ASAN_REPORTER
5195 // In ASan reporter builds, we need to set ASan's log_path as early as
5196 // possible, so it dumps its errors into files there instead of using
5197 // the default stderr location. Since this is crucial for ASan reporter
5198 // to work at all (and we don't want people to use a non-functional
5199 // ASan reporter build), all failures while setting log_path are fatal.
5200 setASanReporterPath(mProfD);
5201
5202 // Export to env for child processes
5203 SaveFileToEnv("ASAN_REPORTER_PATH", mProfD);
5204 #endif
5205
5206 bool lastStartupWasCrash = CheckLastStartupWasCrash().unwrapOr(false);
5207
5208 if (CheckArg("purgecaches") || PR_GetEnv("MOZ_PURGE_CACHES") ||
5209 lastStartupWasCrash || gSafeMode) {
5210 cachesOK = false;
5211 }
5212
5213 // Every time a profile is loaded by a build with a different version,
5214 // it updates the compatibility.ini file saying what version last wrote
5215 // the fastload caches. On subsequent launches if the version matches,
5216 // there is no need for re-registration. If the user loads the same
5217 // profile in different builds the component registry must be
5218 // re-generated to prevent mysterious component loading failures.
5219 //
5220 bool startupCacheValid = true;
5221
5222 if (!cachesOK || !versionOK) {
5223 QuotaManager::InvalidateQuotaCache();
5224
5225 startupCacheValid = RemoveComponentRegistries(mProfD, mProfLD, false);
5226
5227 // Rewrite compatibility.ini to match the current build. The next run
5228 // should attempt to invalidate the caches if either this run is safe mode
5229 // or the attempt to invalidate the caches this time failed.
5230 WriteVersion(mProfD, version, osABI, mDirProvider.GetGREDir(),
5231 mAppData->directory, gSafeMode || !startupCacheValid);
5232 }
5233
5234 if (!startupCacheValid) StartupCache::IgnoreDiskCache();
5235
5236 if (flagFile) {
5237 flagFile->Remove(true);
5238 }
5239
5240 return 0;
5241 }
5242
5243 #if defined(MOZ_SANDBOX)
AddSandboxAnnotations()5244 void AddSandboxAnnotations() {
5245 // Include the sandbox content level, regardless of platform
5246 int level = GetEffectiveContentSandboxLevel();
5247
5248 nsAutoCString levelString;
5249 levelString.AppendInt(level);
5250
5251 CrashReporter::AnnotateCrashReport(
5252 CrashReporter::Annotation::ContentSandboxLevel, levelString);
5253
5254 // Include whether or not this instance is capable of content sandboxing
5255 bool sandboxCapable = false;
5256
5257 # if defined(XP_WIN)
5258 // All supported Windows versions support some level of content sandboxing
5259 sandboxCapable = true;
5260 # elif defined(XP_MACOSX)
5261 // All supported OS X versions are capable
5262 sandboxCapable = true;
5263 # elif defined(XP_LINUX)
5264 sandboxCapable = SandboxInfo::Get().CanSandboxContent();
5265 # elif defined(__OpenBSD__)
5266 sandboxCapable = true;
5267 StartOpenBSDSandbox(GeckoProcessType_Default);
5268 # endif
5269
5270 CrashReporter::AnnotateCrashReport(
5271 CrashReporter::Annotation::ContentSandboxCapable, sandboxCapable);
5272 }
5273 #endif /* MOZ_SANDBOX */
5274
5275 /*
5276 * XRE_mainRun - Command line startup, profile migration, and
5277 * the calling of appStartup->Run().
5278 */
XRE_mainRun()5279 nsresult XREMain::XRE_mainRun() {
5280 nsresult rv = NS_OK;
5281 NS_ASSERTION(mScopedXPCOM, "Scoped xpcom not initialized.");
5282
5283 #if defined(XP_WIN)
5284 RefPtr<mozilla::DllServices> dllServices(mozilla::DllServices::Get());
5285 dllServices->StartUntrustedModulesProcessor(false);
5286 auto dllServicesDisable =
5287 MakeScopeExit([&dllServices]() { dllServices->DisableFull(); });
5288
5289 mozilla::mscom::InitProfilerMarkers();
5290 #endif // defined(XP_WIN)
5291
5292 // We need the appStartup pointer to span multiple scopes, so we declare
5293 // it here.
5294 nsCOMPtr<nsIAppStartup> appStartup;
5295 // Ditto with the command line.
5296 nsCOMPtr<nsICommandLineRunner> cmdLine;
5297
5298 {
5299 #ifdef XP_MACOSX
5300 // In this scope, create an autorelease pool that will leave scope with
5301 // it just before entering our event loop.
5302 mozilla::MacAutoreleasePool pool;
5303 #endif
5304
5305 rv = mScopedXPCOM->SetWindowCreator(mNativeApp);
5306 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
5307
5308 // tell the crash reporter to also send the release channel
5309 nsCOMPtr<nsIPrefService> prefs =
5310 do_GetService("@mozilla.org/preferences-service;1", &rv);
5311 if (NS_SUCCEEDED(rv)) {
5312 nsCOMPtr<nsIPrefBranch> defaultPrefBranch;
5313 rv = prefs->GetDefaultBranch(nullptr, getter_AddRefs(defaultPrefBranch));
5314
5315 if (NS_SUCCEEDED(rv)) {
5316 nsAutoCString sval;
5317 rv = defaultPrefBranch->GetCharPref("app.update.channel", sval);
5318 if (NS_SUCCEEDED(rv)) {
5319 CrashReporter::AnnotateCrashReport(
5320 CrashReporter::Annotation::ReleaseChannel, sval);
5321 }
5322 }
5323 }
5324 // Needs to be set after xpcom initialization.
5325 bool includeContextHeap = Preferences::GetBool(
5326 "toolkit.crashreporter.include_context_heap", false);
5327 CrashReporter::SetIncludeContextHeap(includeContextHeap);
5328
5329 #if defined(XP_LINUX) && !defined(ANDROID)
5330 PR_CreateThread(PR_USER_THREAD, AnnotateLSBRelease, 0, PR_PRIORITY_LOW,
5331 PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD, 0);
5332 #endif
5333
5334 if (mStartOffline) {
5335 nsCOMPtr<nsIIOService> io(
5336 do_GetService("@mozilla.org/network/io-service;1"));
5337 NS_ENSURE_TRUE(io, NS_ERROR_FAILURE);
5338 io->SetManageOfflineStatus(false);
5339 io->SetOffline(true);
5340 }
5341
5342 #ifdef XP_WIN
5343 mozilla::DllPrefetchExperimentRegistryInfo prefetchRegInfo;
5344 mozilla::AlteredDllPrefetchMode dllPrefetchMode =
5345 prefetchRegInfo.GetAlteredDllPrefetchMode();
5346
5347 if (!PR_GetEnv("XRE_NO_DLL_READAHEAD") &&
5348 dllPrefetchMode != mozilla::AlteredDllPrefetchMode::NoPrefetch) {
5349 nsCOMPtr<nsIFile> greDir = mDirProvider.GetGREDir();
5350 nsAutoString path;
5351 rv = greDir->GetPath(path);
5352 if (NS_SUCCEEDED(rv)) {
5353 PRThread* readAheadThread;
5354 wchar_t* pathRaw;
5355
5356 // We use the presence of a path argument inside the thread to determine
5357 // which list of Dlls to use. The old list does not need access to the
5358 // GRE dir, so the path argument is set to a null pointer.
5359 if (dllPrefetchMode ==
5360 mozilla::AlteredDllPrefetchMode::OptimizedPrefetch) {
5361 pathRaw = new wchar_t[MAX_PATH];
5362 wcscpy_s(pathRaw, MAX_PATH, path.get());
5363 } else {
5364 pathRaw = nullptr;
5365 }
5366 readAheadThread = PR_CreateThread(
5367 PR_USER_THREAD, ReadAheadDlls_ThreadStart, (void*)pathRaw,
5368 PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD, 0);
5369 if (readAheadThread == NULL) {
5370 delete[] pathRaw;
5371 }
5372 }
5373 }
5374 #endif
5375
5376 if (gDoMigration) {
5377 nsCOMPtr<nsIFile> file;
5378 mDirProvider.GetAppDir()->Clone(getter_AddRefs(file));
5379 file->AppendNative("override.ini"_ns);
5380 nsINIParser parser;
5381 nsresult rv = parser.Init(file);
5382 // if override.ini doesn't exist, also check for distribution.ini
5383 if (NS_FAILED(rv)) {
5384 bool persistent;
5385 mDirProvider.GetFile(XRE_APP_DISTRIBUTION_DIR, &persistent,
5386 getter_AddRefs(file));
5387 file->AppendNative("distribution.ini"_ns);
5388 rv = parser.Init(file);
5389 }
5390 if (NS_SUCCEEDED(rv)) {
5391 nsAutoCString buf;
5392 rv = parser.GetString("XRE", "EnableProfileMigrator", buf);
5393 if (NS_SUCCEEDED(rv)) {
5394 if (buf[0] == '0' || buf[0] == 'f' || buf[0] == 'F') {
5395 gDoMigration = false;
5396 }
5397 }
5398 }
5399 }
5400
5401 // We'd like to initialize the JSContext *after* reading the user prefs.
5402 // Unfortunately that's not possible if we have to do profile migration
5403 // because that requires us to execute JS before reading user prefs.
5404 // Restarting the browser after profile migration would fix this. See
5405 // bug 1592523.
5406 bool initializedJSContext = false;
5407
5408 {
5409 // Profile Migration
5410 if (mAppData->flags & NS_XRE_ENABLE_PROFILE_MIGRATOR && gDoMigration) {
5411 gDoMigration = false;
5412
5413 xpc::InitializeJSContext();
5414 initializedJSContext = true;
5415
5416 nsCOMPtr<nsIProfileMigrator> pm(
5417 do_CreateInstance(NS_PROFILEMIGRATOR_CONTRACTID));
5418 if (pm) {
5419 nsAutoCString aKey;
5420 nsAutoCString aName;
5421 if (gDoProfileReset) {
5422 // Automatically migrate from the current application if we just
5423 // reset the profile.
5424 aKey = MOZ_APP_NAME;
5425 gResetOldProfile->GetName(aName);
5426 }
5427 pm->Migrate(&mDirProvider, aKey, aName);
5428 }
5429 }
5430
5431 if (gDoProfileReset) {
5432 if (!initializedJSContext) {
5433 xpc::InitializeJSContext();
5434 initializedJSContext = true;
5435 }
5436
5437 nsresult backupCreated =
5438 ProfileResetCleanup(mProfileSvc, gResetOldProfile);
5439 if (NS_FAILED(backupCreated)) {
5440 NS_WARNING("Could not cleanup the profile that was reset");
5441 }
5442 }
5443 }
5444
5445 #ifndef XP_WIN
5446 nsCOMPtr<nsIFile> profileDir;
5447 nsAutoCString path;
5448 rv = mDirProvider.GetProfileStartupDir(getter_AddRefs(profileDir));
5449 if (NS_SUCCEEDED(rv) && NS_SUCCEEDED(profileDir->GetNativePath(path)) &&
5450 !IsUtf8(path)) {
5451 PR_fprintf(
5452 PR_STDERR,
5453 "Error: The profile path is not valid UTF-8. Unable to continue.\n");
5454 return NS_ERROR_FAILURE;
5455 }
5456 #endif
5457
5458 // Initialize user preferences before notifying startup observers so they're
5459 // ready in time for early consumers, such as the component loader.
5460 mDirProvider.InitializeUserPrefs();
5461
5462 // Now that all (user) prefs have been loaded we can initialize the main
5463 // thread's JSContext.
5464 if (!initializedJSContext) {
5465 xpc::InitializeJSContext();
5466 }
5467
5468 // Finally, now that JS has been initialized, we can finish pref loading.
5469 // This needs to happen after JS and XPConnect initialization because
5470 // AutoConfig files require JS execution. Note that this means AutoConfig
5471 // files can't override JS engine start-up prefs.
5472 mDirProvider.FinishInitializingUserPrefs();
5473
5474 nsAppStartupNotifier::NotifyObservers(APPSTARTUP_CATEGORY);
5475
5476 appStartup = components::AppStartup::Service();
5477 NS_ENSURE_TRUE(appStartup, NS_ERROR_FAILURE);
5478
5479 mDirProvider.DoStartup();
5480
5481 // As FilePreferences need the profile directory, we must initialize right
5482 // here.
5483 mozilla::FilePreferences::InitDirectoriesWhitelist();
5484 mozilla::FilePreferences::InitPrefs();
5485
5486 OverrideDefaultLocaleIfNeeded();
5487
5488 nsCString userAgentLocale;
5489 LocaleService::GetInstance()->GetAppLocaleAsBCP47(userAgentLocale);
5490 CrashReporter::AnnotateCrashReport(
5491 CrashReporter::Annotation::useragent_locale, userAgentLocale);
5492
5493 appStartup->GetShuttingDown(&mShuttingDown);
5494
5495 nsCOMPtr<nsIFile> workingDir;
5496 rv = NS_GetSpecialDirectory(NS_OS_CURRENT_WORKING_DIR,
5497 getter_AddRefs(workingDir));
5498 if (NS_FAILED(rv)) {
5499 // No working dir? This can happen if it gets deleted before we start.
5500 workingDir = nullptr;
5501 }
5502
5503 if (!mShuttingDown) {
5504 cmdLine = new nsCommandLine();
5505
5506 rv = cmdLine->Init(gArgc, gArgv, workingDir,
5507 nsICommandLine::STATE_INITIAL_LAUNCH);
5508 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
5509
5510 /* Special-case services that need early access to the command
5511 line. */
5512 nsCOMPtr<nsIObserverService> obsService =
5513 mozilla::services::GetObserverService();
5514 if (obsService) {
5515 obsService->NotifyObservers(cmdLine, "command-line-startup", nullptr);
5516 }
5517 }
5518
5519 #ifdef XP_WIN
5520 // Hack to sync up the various environment storages. XUL_APP_FILE is special
5521 // in that it comes from a different CRT (firefox.exe's static-linked copy).
5522 // Ugly details in http://bugzil.la/1175039#c27
5523 char appFile[MAX_PATH];
5524 if (GetEnvironmentVariableA("XUL_APP_FILE", appFile, sizeof(appFile))) {
5525 SmprintfPointer saved = mozilla::Smprintf("XUL_APP_FILE=%s", appFile);
5526 // We intentionally leak the string here since it is required by
5527 // PR_SetEnv.
5528 PR_SetEnv(saved.release());
5529 }
5530 #endif
5531
5532 mozilla::AppShutdown::SaveEnvVarsForPotentialRestart();
5533
5534 // clear out any environment variables which may have been set
5535 // during the relaunch process now that we know we won't be relaunching.
5536 SaveToEnv("XRE_PROFILE_PATH=");
5537 SaveToEnv("XRE_PROFILE_LOCAL_PATH=");
5538 SaveToEnv("XRE_START_OFFLINE=");
5539 SaveToEnv("XUL_APP_FILE=");
5540 SaveToEnv("XRE_BINARY_PATH=");
5541 SaveToEnv("XRE_RESTARTED_BY_PROFILE_MANAGER=");
5542
5543 if (!mShuttingDown) {
5544 #ifdef XP_MACOSX
5545 bool lazyHiddenWindow = false;
5546 #else
5547 bool lazyHiddenWindow =
5548 Preferences::GetBool("toolkit.lazyHiddenWindow", false);
5549 #endif
5550
5551 #ifdef MOZ_BACKGROUNDTASKS
5552 if (BackgroundTasks::IsBackgroundTaskMode()) {
5553 // Background tasks aren't going to load a chrome XUL document.
5554 lazyHiddenWindow = true;
5555 }
5556 #endif
5557
5558 if (!lazyHiddenWindow) {
5559 rv = appStartup->CreateHiddenWindow();
5560 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
5561 }
5562
5563 #ifdef XP_WIN
5564 Preferences::RegisterCallbackAndCall(
5565 RegisterApplicationRestartChanged,
5566 PREF_WIN_REGISTER_APPLICATION_RESTART);
5567 SetupAlteredPrefetchPref();
5568 SetupSkeletonUIPrefs();
5569 # if defined(MOZ_LAUNCHER_PROCESS)
5570 SetupLauncherProcessPref();
5571 # endif // defined(MOZ_LAUNCHER_PROCESS)
5572 # if defined(MOZ_DEFAULT_BROWSER_AGENT)
5573 # if defined(MOZ_BACKGROUNDTASKS)
5574 // The backgroundtask profile is not a browsing profile, let alone the new
5575 // default profile, so don't mirror its properties into the registry.
5576 if (!BackgroundTasks::IsBackgroundTaskMode())
5577 # endif // defined(MOZ_BACKGROUNDTASKS)
5578 {
5579 Preferences::RegisterCallbackAndCall(
5580 &OnDefaultAgentTelemetryPrefChanged,
5581 kPrefHealthReportUploadEnabled);
5582 Preferences::RegisterCallbackAndCall(
5583 &OnDefaultAgentTelemetryPrefChanged, kPrefDefaultAgentEnabled);
5584
5585 Preferences::RegisterCallbackAndCall(
5586 &OnDefaultAgentRemoteSettingsPrefChanged,
5587 kPrefServicesSettingsServer);
5588 Preferences::RegisterCallbackAndCall(
5589 &OnDefaultAgentRemoteSettingsPrefChanged,
5590 kPrefSecurityContentSignatureRootHash);
5591
5592 Preferences::RegisterCallbackAndCall(
5593 &OnSetDefaultBrowserUserChoicePrefChanged,
5594 kPrefSetDefaultBrowserUserChoicePref);
5595
5596 SetDefaultAgentLastRunTime();
5597 }
5598 # endif // defined(MOZ_DEFAULT_BROWSER_AGENT)
5599 #endif
5600
5601 #if defined(HAVE_DESKTOP_STARTUP_ID) && defined(MOZ_WIDGET_GTK)
5602 // Clear the environment variable so it won't be inherited by
5603 // child processes and confuse things.
5604 g_unsetenv("DESKTOP_STARTUP_ID");
5605 #endif
5606
5607 #ifdef XP_MACOSX
5608 // we re-initialize the command-line service and do appleevents munging
5609 // after we are sure that we're not restarting
5610 cmdLine = new nsCommandLine();
5611
5612 char** tempArgv = static_cast<char**>(malloc(gArgc * sizeof(char*)));
5613 for (int i = 0; i < gArgc; i++) {
5614 tempArgv[i] = strdup(gArgv[i]);
5615 }
5616 CommandLineServiceMac::SetupMacCommandLine(gArgc, tempArgv, false);
5617 rv = cmdLine->Init(gArgc, tempArgv, workingDir,
5618 nsICommandLine::STATE_INITIAL_LAUNCH);
5619 free(tempArgv);
5620 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
5621
5622 # ifdef MOZILLA_OFFICIAL
5623 // Check if we're running from a DMG and allow the user to install to the
5624 // Applications directory.
5625 if (MacRunFromDmgUtils::MaybeInstallFromDmgAndRelaunch()) {
5626 bool userAllowedQuit = true;
5627 appStartup->Quit(nsIAppStartup::eForceQuit, 0, &userAllowedQuit);
5628 }
5629 # endif
5630 #endif
5631
5632 nsCOMPtr<nsIObserverService> obsService =
5633 mozilla::services::GetObserverService();
5634 if (obsService)
5635 obsService->NotifyObservers(nullptr, "final-ui-startup", nullptr);
5636
5637 (void)appStartup->DoneStartingUp();
5638
5639 CrashReporter::AnnotateCrashReport(
5640 CrashReporter::Annotation::StartupCrash, false);
5641
5642 appStartup->GetShuttingDown(&mShuttingDown);
5643 }
5644
5645 if (!mShuttingDown) {
5646 rv = cmdLine->Run();
5647 NS_ENSURE_SUCCESS_LOG(rv, NS_ERROR_FAILURE);
5648
5649 appStartup->GetShuttingDown(&mShuttingDown);
5650 }
5651
5652 if (!mShuttingDown) {
5653 #if defined(MOZ_HAS_REMOTE)
5654 // if we have X remote support, start listening for requests on the
5655 // proxy window.
5656 if (mRemoteService && !mDisableRemoteServer) {
5657 mRemoteService->StartupServer();
5658 mRemoteService->UnlockStartup();
5659 gRemoteService = nullptr;
5660 }
5661 #endif /* MOZ_WIDGET_GTK */
5662
5663 mNativeApp->Enable();
5664 }
5665
5666 #ifdef MOZ_INSTRUMENT_EVENT_LOOP
5667 if (PR_GetEnv("MOZ_INSTRUMENT_EVENT_LOOP")) {
5668 bool logToConsole = true;
5669 mozilla::InitEventTracing(logToConsole);
5670 }
5671 #endif /* MOZ_INSTRUMENT_EVENT_LOOP */
5672
5673 // Send Telemetry about Gecko version and buildid
5674 Telemetry::ScalarSet(Telemetry::ScalarID::GECKO_VERSION,
5675 NS_ConvertASCIItoUTF16(gAppData->version));
5676 Telemetry::ScalarSet(Telemetry::ScalarID::GECKO_BUILD_ID,
5677 NS_ConvertASCIItoUTF16(gAppData->buildID));
5678
5679 #if defined(MOZ_SANDBOX) && defined(XP_LINUX)
5680 // If we're on Linux, we now have information about the OS capabilities
5681 // available to us.
5682 SandboxInfo sandboxInfo = SandboxInfo::Get();
5683 Telemetry::Accumulate(Telemetry::SANDBOX_HAS_SECCOMP_BPF,
5684 sandboxInfo.Test(SandboxInfo::kHasSeccompBPF));
5685 Telemetry::Accumulate(Telemetry::SANDBOX_HAS_SECCOMP_TSYNC,
5686 sandboxInfo.Test(SandboxInfo::kHasSeccompTSync));
5687 Telemetry::Accumulate(
5688 Telemetry::SANDBOX_HAS_USER_NAMESPACES_PRIVILEGED,
5689 sandboxInfo.Test(SandboxInfo::kHasPrivilegedUserNamespaces));
5690 Telemetry::Accumulate(Telemetry::SANDBOX_HAS_USER_NAMESPACES,
5691 sandboxInfo.Test(SandboxInfo::kHasUserNamespaces));
5692 Telemetry::Accumulate(Telemetry::SANDBOX_CONTENT_ENABLED,
5693 sandboxInfo.Test(SandboxInfo::kEnabledForContent));
5694 Telemetry::Accumulate(Telemetry::SANDBOX_MEDIA_ENABLED,
5695 sandboxInfo.Test(SandboxInfo::kEnabledForMedia));
5696 nsAutoCString flagsString;
5697 flagsString.AppendInt(sandboxInfo.AsInteger());
5698
5699 CrashReporter::AnnotateCrashReport(
5700 CrashReporter::Annotation::ContentSandboxCapabilities, flagsString);
5701 #endif /* MOZ_SANDBOX && XP_LINUX */
5702
5703 #if defined(XP_WIN)
5704 LauncherResult<bool> isAdminWithoutUac = IsAdminWithoutUac();
5705 if (isAdminWithoutUac.isOk()) {
5706 Telemetry::ScalarSet(
5707 Telemetry::ScalarID::OS_ENVIRONMENT_IS_ADMIN_WITHOUT_UAC,
5708 isAdminWithoutUac.unwrap());
5709 }
5710 #endif /* XP_WIN */
5711
5712 #if defined(MOZ_SANDBOX)
5713 AddSandboxAnnotations();
5714 #endif /* MOZ_SANDBOX */
5715
5716 mProfileSvc->CompleteStartup();
5717 }
5718
5719 #ifdef MOZ_BACKGROUNDTASKS
5720 if (BackgroundTasks::IsBackgroundTaskMode()) {
5721 // In background task mode, we don't fire various delayed initialization
5722 // notifications, which in the regular browser is how startup crash tracking
5723 // is marked as finished. Here, getting this far means we don't have a
5724 // startup crash.
5725 rv = appStartup->TrackStartupCrashEnd();
5726 NS_ENSURE_SUCCESS(rv, rv);
5727
5728 // We never open a window, but don't want to exit immediately.
5729 rv = appStartup->EnterLastWindowClosingSurvivalArea();
5730 NS_ENSURE_SUCCESS(rv, rv);
5731
5732 // Avoid some small differences in initialization order across platforms.
5733 nsCOMPtr<nsIPowerManagerService> powerManagerService =
5734 do_GetService(POWERMANAGERSERVICE_CONTRACTID);
5735 nsCOMPtr<nsIStringBundleService> stringBundleService =
5736 do_GetService(NS_STRINGBUNDLE_CONTRACTID);
5737
5738 rv = BackgroundTasks::RunBackgroundTask(cmdLine);
5739 NS_ENSURE_SUCCESS(rv, rv);
5740 }
5741 #endif
5742
5743 {
5744 rv = appStartup->Run();
5745 if (NS_FAILED(rv)) {
5746 NS_ERROR("failed to run appstartup");
5747 gLogConsoleErrors = true;
5748 }
5749 }
5750
5751 return rv;
5752 }
5753
5754 #if defined(MOZ_WIDGET_ANDROID)
GreOmniPath(int argc,char ** argv)5755 static already_AddRefed<nsIFile> GreOmniPath(int argc, char** argv) {
5756 nsresult rv;
5757
5758 const char* path = nullptr;
5759 ArgResult ar = CheckArg(argc, argv, "greomni", &path, CheckArgFlag::None);
5760 if (ar == ARG_BAD) {
5761 PR_fprintf(PR_STDERR,
5762 "Error: argument --greomni requires a path argument\n");
5763 return nullptr;
5764 }
5765
5766 if (!path) return nullptr;
5767
5768 nsCOMPtr<nsIFile> greOmni;
5769 rv = XRE_GetFileFromPath(path, getter_AddRefs(greOmni));
5770 if (NS_FAILED(rv)) {
5771 PR_fprintf(PR_STDERR, "Error: argument --greomni requires a valid path\n");
5772 return nullptr;
5773 }
5774
5775 return greOmni.forget();
5776 }
5777 #endif
5778
5779 /*
5780 * XRE_main - A class based main entry point used by most platforms.
5781 * Note that on OSX, aAppData->xreDirectory will point to
5782 * .app/Contents/Resources.
5783 */
XRE_main(int argc,char * argv[],const BootstrapConfig & aConfig)5784 int XREMain::XRE_main(int argc, char* argv[], const BootstrapConfig& aConfig) {
5785 gArgc = argc;
5786 gArgv = argv;
5787
5788 ScopedLogging log;
5789
5790 mozilla::LogModule::Init(gArgc, gArgv);
5791
5792 #ifndef XP_LINUX
5793 NS_SetCurrentThreadName("MainThread");
5794 #endif
5795
5796 AUTO_BASE_PROFILER_LABEL("XREMain::XRE_main (around Gecko Profiler)", OTHER);
5797 AUTO_PROFILER_INIT;
5798 AUTO_PROFILER_LABEL("XREMain::XRE_main", OTHER);
5799
5800 #ifdef XP_MACOSX
5801 // We call this early because it will kick off a background-thread task
5802 // to register the fonts, and we'd like it to have a chance to complete
5803 // before gfxPlatform initialization actually requires it.
5804 gfxPlatformMac::RegisterSupplementalFonts();
5805 #endif
5806
5807 #ifdef MOZ_CODE_COVERAGE
5808 CodeCoverageHandler::Init();
5809 #endif
5810
5811 nsresult rv = NS_OK;
5812
5813 if (aConfig.appData) {
5814 mAppData = MakeUnique<XREAppData>(*aConfig.appData);
5815 } else {
5816 MOZ_RELEASE_ASSERT(aConfig.appDataPath);
5817 nsCOMPtr<nsIFile> appini;
5818 rv = XRE_GetFileFromPath(aConfig.appDataPath, getter_AddRefs(appini));
5819 if (NS_FAILED(rv)) {
5820 Output(true, "Error: unrecognized path: %s\n", aConfig.appDataPath);
5821 return 1;
5822 }
5823
5824 mAppData = MakeUnique<XREAppData>();
5825 rv = XRE_ParseAppData(appini, *mAppData);
5826 if (NS_FAILED(rv)) {
5827 Output(true, "Couldn't read application.ini");
5828 return 1;
5829 }
5830
5831 appini->GetParent(getter_AddRefs(mAppData->directory));
5832 }
5833
5834 if (!mAppData->remotingName) {
5835 mAppData->remotingName = mAppData->name;
5836 }
5837 // used throughout this file
5838 gAppData = mAppData.get();
5839
5840 nsCOMPtr<nsIFile> binFile;
5841 rv = XRE_GetBinaryPath(getter_AddRefs(binFile));
5842 NS_ENSURE_SUCCESS(rv, 1);
5843
5844 rv = binFile->GetPath(gAbsoluteArgv0Path);
5845 NS_ENSURE_SUCCESS(rv, 1);
5846
5847 if (!mAppData->xreDirectory) {
5848 nsCOMPtr<nsIFile> greDir;
5849
5850 #if defined(MOZ_WIDGET_ANDROID)
5851 greDir = GreOmniPath(argc, argv);
5852 if (!greDir) {
5853 return 2;
5854 }
5855 #else
5856 rv = binFile->GetParent(getter_AddRefs(greDir));
5857 if (NS_FAILED(rv)) return 2;
5858 #endif
5859
5860 #ifdef XP_MACOSX
5861 nsCOMPtr<nsIFile> parent;
5862 greDir->GetParent(getter_AddRefs(parent));
5863 greDir = parent.forget();
5864 greDir->AppendNative("Resources"_ns);
5865 #endif
5866
5867 mAppData->xreDirectory = greDir;
5868 }
5869
5870 #if defined(MOZ_WIDGET_ANDROID)
5871 nsCOMPtr<nsIFile> dataDir;
5872 rv = binFile->GetParent(getter_AddRefs(dataDir));
5873 if (NS_FAILED(rv)) return 2;
5874
5875 mAppData->directory = dataDir;
5876 #else
5877 if (aConfig.appData && aConfig.appDataPath) {
5878 mAppData->xreDirectory->Clone(getter_AddRefs(mAppData->directory));
5879 mAppData->directory->AppendNative(nsDependentCString(aConfig.appDataPath));
5880 }
5881 #endif
5882
5883 if (!mAppData->directory) {
5884 mAppData->directory = mAppData->xreDirectory;
5885 }
5886
5887 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
5888 mAppData->sandboxBrokerServices = aConfig.sandboxBrokerServices;
5889 mAppData->sandboxPermissionsService = aConfig.sandboxPermissionsService;
5890 #endif
5891
5892 mozilla::IOInterposerInit ioInterposerGuard;
5893
5894 #if defined(XP_WIN)
5895 // We should have already done this when we created the skeleton UI. However,
5896 // there is code in here which needs xul in order to work, like EnsureMTA. It
5897 // should be setup that running it again is safe.
5898 mozilla::mscom::ProcessRuntime msCOMRuntime;
5899 #endif
5900
5901 // init
5902 bool exit = false;
5903 int result = XRE_mainInit(&exit);
5904 if (result != 0 || exit) return result;
5905
5906 // If we exit gracefully, remove the startup crash canary file.
5907 auto cleanup = MakeScopeExit([&]() -> nsresult {
5908 if (mProfLD) {
5909 nsCOMPtr<nsIFile> crashFile;
5910 MOZ_TRY_VAR(crashFile, GetIncompleteStartupFile(mProfLD));
5911 crashFile->Remove(false);
5912 }
5913 return NS_OK;
5914 });
5915
5916 // startup
5917 result = XRE_mainStartup(&exit);
5918 if (result != 0 || exit) return result;
5919
5920 // Start the real application. We use |aInitJSContext = false| because
5921 // XRE_mainRun wants to initialize the JSContext after reading user prefs.
5922
5923 mScopedXPCOM = MakeUnique<ScopedXPCOMStartup>();
5924
5925 rv = mScopedXPCOM->Initialize(/* aInitJSContext = */ false);
5926 NS_ENSURE_SUCCESS(rv, 1);
5927
5928 // run!
5929 rv = XRE_mainRun();
5930
5931 #ifdef MOZ_INSTRUMENT_EVENT_LOOP
5932 mozilla::ShutdownEventTracing();
5933 #endif
5934
5935 gAbsoluteArgv0Path.Truncate();
5936
5937 #if defined(MOZ_HAS_REMOTE)
5938 // Shut down the remote service. We must do this before calling LaunchChild
5939 // if we're restarting because otherwise the new instance will attempt to
5940 // remote to this instance.
5941 if (mRemoteService && !mDisableRemoteServer) {
5942 mRemoteService->ShutdownServer();
5943 }
5944 #endif /* MOZ_WIDGET_GTK */
5945
5946 mScopedXPCOM = nullptr;
5947
5948 #if defined(XP_WIN)
5949 mozilla::widget::StopAudioSession();
5950 #endif
5951
5952 // unlock the profile after ScopedXPCOMStartup object (xpcom)
5953 // has gone out of scope. see bug #386739 for more details
5954 mProfileLock->Unlock();
5955 gProfileLock = nullptr;
5956
5957 gLastAppVersion.Truncate();
5958 gLastAppBuildID.Truncate();
5959
5960 mozilla::AppShutdown::MaybeDoRestart();
5961
5962 #ifdef MOZ_WIDGET_GTK
5963 // gdk_display_close also calls gdk_display_manager_set_default_display
5964 // appropriately when necessary.
5965 if (!gfxPlatform::IsHeadless()) {
5966 # ifdef MOZ_WAYLAND
5967 WaylandDisplayRelease();
5968 # endif
5969 }
5970 #endif
5971
5972 if (mAppData->flags & NS_XRE_ENABLE_CRASH_REPORTER)
5973 CrashReporter::UnsetExceptionHandler();
5974
5975 XRE_DeinitCommandLine();
5976
5977 if (NS_FAILED(rv)) {
5978 return 1;
5979 }
5980 return mozilla::AppShutdown::GetExitCode();
5981 }
5982
XRE_StopLateWriteChecks(void)5983 void XRE_StopLateWriteChecks(void) { mozilla::StopLateWriteChecks(); }
5984
XRE_main(int argc,char * argv[],const BootstrapConfig & aConfig)5985 int XRE_main(int argc, char* argv[], const BootstrapConfig& aConfig) {
5986 XREMain main;
5987
5988 int result = main.XRE_main(argc, argv, aConfig);
5989 mozilla::RecordShutdownEndTimeStamp();
5990 #ifdef MOZ_BACKGROUNDTASKS
5991 // This is well after the profile has been unlocked, so it's okay if this does
5992 // delete this background task's temporary profile.
5993 mozilla::BackgroundTasks::Shutdown();
5994 #endif
5995 return result;
5996 }
5997
XRE_InitCommandLine(int aArgc,char * aArgv[])5998 nsresult XRE_InitCommandLine(int aArgc, char* aArgv[]) {
5999 nsresult rv = NS_OK;
6000
6001 #if defined(OS_WIN)
6002 CommandLine::Init(aArgc, aArgv);
6003 #else
6004
6005 // these leak on error, but that's OK: we'll just exit()
6006 char** canonArgs = new char*[aArgc];
6007
6008 // get the canonical version of the binary's path
6009 nsCOMPtr<nsIFile> binFile;
6010 rv = XRE_GetBinaryPath(getter_AddRefs(binFile));
6011 if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
6012
6013 nsAutoCString canonBinPath;
6014 rv = binFile->GetNativePath(canonBinPath);
6015 if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
6016
6017 canonArgs[0] = strdup(canonBinPath.get());
6018
6019 for (int i = 1; i < aArgc; ++i) {
6020 if (aArgv[i]) {
6021 canonArgs[i] = strdup(aArgv[i]);
6022 }
6023 }
6024
6025 NS_ASSERTION(!CommandLine::IsInitialized(), "Bad news!");
6026 CommandLine::Init(aArgc, canonArgs);
6027
6028 for (int i = 0; i < aArgc; ++i) free(canonArgs[i]);
6029 delete[] canonArgs;
6030 #endif
6031
6032 #if defined(MOZ_WIDGET_ANDROID)
6033 nsCOMPtr<nsIFile> greOmni =
6034 gAppData ? gAppData->xreDirectory : GreOmniPath(aArgc, aArgv);
6035 if (!greOmni) {
6036 return NS_ERROR_FAILURE;
6037 }
6038 mozilla::Omnijar::Init(greOmni, greOmni);
6039 #endif
6040
6041 return rv;
6042 }
6043
XRE_DeinitCommandLine()6044 nsresult XRE_DeinitCommandLine() {
6045 nsresult rv = NS_OK;
6046
6047 CommandLine::Terminate();
6048
6049 return rv;
6050 }
6051
XRE_GetProcessType()6052 GeckoProcessType XRE_GetProcessType() {
6053 return mozilla::startup::sChildProcessType;
6054 }
6055
XRE_GetProcessTypeString()6056 const char* XRE_GetProcessTypeString() {
6057 return XRE_GeckoProcessTypeToString(XRE_GetProcessType());
6058 }
6059
XRE_IsE10sParentProcess()6060 bool XRE_IsE10sParentProcess() {
6061 #ifdef MOZ_WIDGET_ANDROID
6062 return XRE_IsParentProcess() && BrowserTabsRemoteAutostart() &&
6063 mozilla::jni::IsAvailable();
6064 #else
6065 return XRE_IsParentProcess() && BrowserTabsRemoteAutostart();
6066 #endif
6067 }
6068
6069 #define GECKO_PROCESS_TYPE(enum_value, enum_name, string_name, proc_typename, \
6070 process_bin_type, procinfo_typename, \
6071 webidl_typename, allcaps_name) \
6072 bool XRE_Is##proc_typename##Process() { \
6073 return XRE_GetProcessType() == GeckoProcessType_##enum_name; \
6074 }
6075 #include "mozilla/GeckoProcessTypes.h"
6076 #undef GECKO_PROCESS_TYPE
6077
XRE_UseNativeEventProcessing()6078 bool XRE_UseNativeEventProcessing() {
6079 #if defined(XP_MACOSX) || defined(XP_WIN)
6080 if (XRE_IsRDDProcess() || XRE_IsSocketProcess() || XRE_IsUtilityProcess()) {
6081 return false;
6082 }
6083 #endif
6084 if (XRE_IsContentProcess()) {
6085 return StaticPrefs::dom_ipc_useNativeEventProcessing_content();
6086 }
6087
6088 return true;
6089 }
6090
6091 namespace mozilla {
6092
GetMaxWebProcessCount()6093 uint32_t GetMaxWebProcessCount() {
6094 // multiOptOut is in int to allow us to run multiple experiments without
6095 // introducing multiple prefs a la the autostart.N prefs.
6096 if (Preferences::GetInt("dom.ipc.multiOptOut", 0) >=
6097 nsIXULRuntime::E10S_MULTI_EXPERIMENT) {
6098 return 1;
6099 }
6100
6101 const char* optInPref = "dom.ipc.processCount";
6102 uint32_t optInPrefValue = Preferences::GetInt(optInPref, 1);
6103 return std::max(1u, optInPrefValue);
6104 }
6105
PlatformBuildID()6106 const char* PlatformBuildID() { return gToolkitBuildID; }
6107
6108 } // namespace mozilla
6109
SetupErrorHandling(const char * progname)6110 void SetupErrorHandling(const char* progname) {
6111 #ifdef XP_WIN
6112 /* On Windows XPSP3 and Windows Vista if DEP is configured off-by-default
6113 we still want DEP protection: enable it explicitly and programmatically.
6114
6115 This function is not available on WinXPSP2 so we dynamically load it.
6116 */
6117
6118 HMODULE kernel32 = GetModuleHandleW(L"kernel32.dll");
6119 SetProcessDEPPolicyFunc _SetProcessDEPPolicy =
6120 (SetProcessDEPPolicyFunc)GetProcAddress(kernel32, "SetProcessDEPPolicy");
6121 if (_SetProcessDEPPolicy) _SetProcessDEPPolicy(PROCESS_DEP_ENABLE);
6122 #endif
6123
6124 #ifdef XP_WIN
6125 // Suppress the "DLL Foo could not be found" dialog, such that if dependent
6126 // libraries (such as GDI+) are not preset, we gracefully fail to load those
6127 // XPCOM components, instead of being ungraceful.
6128 UINT realMode = SetErrorMode(0);
6129 realMode |= SEM_FAILCRITICALERRORS;
6130 // If XRE_NO_WINDOWS_CRASH_DIALOG is set, suppress displaying the "This
6131 // application has crashed" dialog box. This is mainly useful for
6132 // automated testing environments, e.g. tinderbox, where there's no need
6133 // for a dozen of the dialog boxes to litter the console
6134 if (getenv("XRE_NO_WINDOWS_CRASH_DIALOG"))
6135 realMode |= SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX;
6136
6137 SetErrorMode(realMode);
6138
6139 #endif
6140
6141 InstallSignalHandlers(progname);
6142
6143 // Unbuffer stdout, needed for tinderbox tests.
6144 setbuf(stdout, 0);
6145 }
6146
6147 // Note: This function should not be needed anymore. See Bug 818634 for details.
OverrideDefaultLocaleIfNeeded()6148 void OverrideDefaultLocaleIfNeeded() {
6149 // Read pref to decide whether to override default locale with US English.
6150 if (mozilla::Preferences::GetBool("javascript.use_us_english_locale",
6151 false)) {
6152 // Set the application-wide C-locale. Needed to resist fingerprinting
6153 // of Date.toLocaleFormat(). We use the locale to "C.UTF-8" if possible,
6154 // to avoid interfering with non-ASCII keyboard input on some Linux
6155 // desktops. Otherwise fall back to the "C" locale, which is available on
6156 // all platforms.
6157 setlocale(LC_ALL, "C.UTF-8") || setlocale(LC_ALL, "C");
6158 }
6159 }
6160
6161 static bool gRunSelfAsContentProc = false;
6162
XRE_EnableSameExecutableForContentProc()6163 void XRE_EnableSameExecutableForContentProc() {
6164 if (!PR_GetEnv("MOZ_SEPARATE_CHILD_PROCESS")) {
6165 gRunSelfAsContentProc = true;
6166 }
6167 }
6168
XRE_GetChildProcBinPathType(GeckoProcessType aProcessType)6169 mozilla::BinPathType XRE_GetChildProcBinPathType(
6170 GeckoProcessType aProcessType) {
6171 MOZ_ASSERT(aProcessType != GeckoProcessType_Default);
6172
6173 if (!gRunSelfAsContentProc) {
6174 return BinPathType::PluginContainer;
6175 }
6176
6177 switch (aProcessType) {
6178 #define GECKO_PROCESS_TYPE(enum_value, enum_name, string_name, proc_typename, \
6179 process_bin_type, procinfo_typename, \
6180 webidl_typename, allcaps_name) \
6181 case GeckoProcessType_##enum_name: \
6182 return BinPathType::process_bin_type;
6183 #include "mozilla/GeckoProcessTypes.h"
6184 #undef GECKO_PROCESS_TYPE
6185 default:
6186 return BinPathType::PluginContainer;
6187 }
6188 }
6189
6190 // From mozglue/static/rust/lib.rs
6191 extern "C" void install_rust_panic_hook();
6192 extern "C" void install_rust_oom_hook();
6193
6194 struct InstallRustHooks {
InstallRustHooksInstallRustHooks6195 InstallRustHooks() {
6196 install_rust_panic_hook();
6197 install_rust_oom_hook();
6198 }
6199 };
6200
6201 InstallRustHooks sInstallRustHooks;
6202
6203 #ifdef MOZ_ASAN_REPORTER
setASanReporterPath(nsIFile * aDir)6204 void setASanReporterPath(nsIFile* aDir) {
6205 nsCOMPtr<nsIFile> dir;
6206 aDir->Clone(getter_AddRefs(dir));
6207
6208 dir->Append(u"asan"_ns);
6209 nsresult rv = dir->Create(nsIFile::DIRECTORY_TYPE, 0700);
6210 if (NS_WARN_IF(NS_FAILED(rv) && rv != NS_ERROR_FILE_ALREADY_EXISTS)) {
6211 MOZ_CRASH("[ASan Reporter] Unable to create crash directory.");
6212 }
6213
6214 dir->Append(u"ff_asan_log"_ns);
6215
6216 # ifdef XP_WIN
6217 nsAutoString nspathW;
6218 rv = dir->GetPath(nspathW);
6219 NS_ConvertUTF16toUTF8 nspath(nspathW);
6220 # else
6221 nsAutoCString nspath;
6222 rv = dir->GetNativePath(nspath);
6223 # endif
6224 if (NS_FAILED(rv)) {
6225 MOZ_CRASH("[ASan Reporter] Unable to get native path for crash directory.");
6226 }
6227
6228 __sanitizer_set_report_path(nspath.get());
6229 }
6230 #endif
6231