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