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