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