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/ArrayUtils.h"
11 #include "mozilla/Attributes.h"
12 #include "mozilla/ChaosMode.h"
13 #include "mozilla/IOInterposer.h"
14 #include "mozilla/Likely.h"
15 #include "mozilla/MemoryChecking.h"
16 #include "mozilla/Poison.h"
17 #include "mozilla/Preferences.h"
18 #include "mozilla/ScopeExit.h"
19 #include "mozilla/Services.h"
20 #include "mozilla/ServoBindings.h"
21 #include "mozilla/Telemetry.h"
22 
23 #include "nsAppRunner.h"
24 #include "mozilla/AppData.h"
25 #if defined(MOZ_UPDATER) && !defined(MOZ_WIDGET_ANDROID)
26 #include "nsUpdateDriver.h"
27 #endif
28 #include "ProfileReset.h"
29 
30 #ifdef MOZ_INSTRUMENT_EVENT_LOOP
31 #include "EventTracer.h"
32 #endif
33 
34 #ifdef XP_MACOSX
35 #include "nsVersionComparator.h"
36 #include "MacLaunchHelper.h"
37 #include "MacApplicationDelegate.h"
38 #include "MacAutoreleasePool.h"
39 // these are needed for sysctl
40 #include <sys/types.h>
41 #include <sys/sysctl.h>
42 #endif
43 
44 #include "prmem.h"
45 #include "prnetdb.h"
46 #include "prprf.h"
47 #include "prproces.h"
48 #include "prenv.h"
49 #include "prtime.h"
50 
51 #include "nsIAppShellService.h"
52 #include "nsIAppStartup.h"
53 #include "nsIAppStartupNotifier.h"
54 #include "nsIMutableArray.h"
55 #include "nsICategoryManager.h"
56 #include "nsIChromeRegistry.h"
57 #include "nsICommandLineRunner.h"
58 #include "nsIComponentManager.h"
59 #include "nsIComponentRegistrar.h"
60 #include "nsIConsoleService.h"
61 #include "nsIContentHandler.h"
62 #include "nsIDialogParamBlock.h"
63 #include "nsIDOMWindow.h"
64 #include "mozilla/ModuleUtils.h"
65 #include "nsIIOService2.h"
66 #include "nsIObserverService.h"
67 #include "nsINativeAppSupport.h"
68 #include "nsIPlatformInfo.h"
69 #include "nsIProcess.h"
70 #include "nsIProfileUnlocker.h"
71 #include "nsIPromptService.h"
72 #include "nsIServiceManager.h"
73 #include "nsIStringBundle.h"
74 #include "nsISupportsPrimitives.h"
75 #include "nsIToolkitChromeRegistry.h"
76 #include "nsIToolkitProfile.h"
77 #include "nsIToolkitProfileService.h"
78 #include "nsIURI.h"
79 #include "nsIURL.h"
80 #include "nsIWindowCreator.h"
81 #include "nsIWindowMediator.h"
82 #include "nsIWindowWatcher.h"
83 #include "nsIXULAppInfo.h"
84 #include "nsIXULRuntime.h"
85 #include "nsPIDOMWindow.h"
86 #include "nsIBaseWindow.h"
87 #include "nsIWidget.h"
88 #include "nsIDocShell.h"
89 #include "nsAppShellCID.h"
90 #include "mozilla/scache/StartupCache.h"
91 #include "gfxPrefs.h"
92 
93 #include "mozilla/Unused.h"
94 
95 #ifdef XP_WIN
96 #include "nsIWinAppHelper.h"
97 #include <windows.h>
98 #include <intrin.h>
99 #include <math.h>
100 #include "cairo/cairo-features.h"
101 #include "mozilla/WindowsVersion.h"
102 #include "mozilla/mscom/MainThreadRuntime.h"
103 #include "mozilla/widget/AudioSession.h"
104 
105 #ifndef PROCESS_DEP_ENABLE
106 #define PROCESS_DEP_ENABLE 0x1
107 #endif
108 #endif
109 
110 #if (defined(XP_WIN) || defined(XP_MACOSX)) && defined(MOZ_CONTENT_SANDBOX)
111 #include "nsIUUIDGenerator.h"
112 #endif
113 
114 #ifdef ACCESSIBILITY
115 #include "nsAccessibilityService.h"
116 #if defined(XP_WIN)
117 #include "mozilla/a11y/Compatibility.h"
118 #endif
119 #endif
120 
121 #include "nsCRT.h"
122 #include "nsCOMPtr.h"
123 #include "nsDirectoryServiceDefs.h"
124 #include "nsDirectoryServiceUtils.h"
125 #include "nsEmbedCID.h"
126 #include "nsNetUtil.h"
127 #include "nsReadableUtils.h"
128 #include "nsXPCOM.h"
129 #include "nsXPCOMCIDInternal.h"
130 #include "nsXPIDLString.h"
131 #include "nsPrintfCString.h"
132 #include "nsVersionComparator.h"
133 
134 #include "nsAppDirectoryServiceDefs.h"
135 #include "nsXULAppAPI.h"
136 #include "nsXREDirProvider.h"
137 #include "nsToolkitCompsCID.h"
138 
139 #include "nsINIParser.h"
140 #include "mozilla/Omnijar.h"
141 #include "mozilla/StartupTimeline.h"
142 #include "mozilla/LateWriteChecks.h"
143 
144 #include <stdlib.h>
145 #include <locale.h>
146 
147 #ifdef XP_UNIX
148 #include <sys/stat.h>
149 #include <unistd.h>
150 #include <pwd.h>
151 #endif
152 
153 #ifdef XP_WIN
154 #include <process.h>
155 #include <shlobj.h>
156 #include "nsThreadUtils.h"
157 #include <comdef.h>
158 #include <wbemidl.h>
159 #include "WinUtils.h"
160 #endif
161 
162 #ifdef XP_MACOSX
163 #include "nsILocalFileMac.h"
164 #include "nsCommandLineServiceMac.h"
165 #endif
166 
167 // for X remote support
168 #ifdef MOZ_ENABLE_XREMOTE
169 #include "XRemoteClient.h"
170 #include "nsIRemoteService.h"
171 #include "nsProfileLock.h"
172 #include "SpecialSystemDirectory.h"
173 #include <sched.h>
174 // Time to wait for the remoting service to start
175 #define MOZ_XREMOTE_START_TIMEOUT_SEC 5
176 #endif
177 
178 #if defined(DEBUG) && defined(XP_WIN32)
179 #include <malloc.h>
180 #endif
181 
182 #if defined (XP_MACOSX)
183 #include <Carbon/Carbon.h>
184 #endif
185 
186 #ifdef DEBUG
187 #include "mozilla/Logging.h"
188 #endif
189 
190 #ifdef MOZ_JPROF
191 #include "jprof.h"
192 #endif
193 
194 #ifdef MOZ_CRASHREPORTER
195 #include "nsExceptionHandler.h"
196 #include "nsICrashReporter.h"
197 #define NS_CRASHREPORTER_CONTRACTID "@mozilla.org/toolkit/crash-reporter;1"
198 #include "nsIPrefService.h"
199 #include "nsIMemoryInfoDumper.h"
200 #if defined(XP_LINUX) && !defined(ANDROID)
201 #include "mozilla/widget/LSBUtils.h"
202 #endif
203 #endif
204 
205 #include "base/command_line.h"
206 #include "GTestRunner.h"
207 
208 #ifdef MOZ_WIDGET_ANDROID
209 #include "GeneratedJNIWrappers.h"
210 #endif
211 
212 #if defined(MOZ_SANDBOX)
213 #if defined(XP_LINUX) && !defined(ANDROID)
214 #include "mozilla/SandboxInfo.h"
215 #elif defined(XP_WIN)
216 #include "SandboxBroker.h"
217 #endif
218 #endif
219 
220 extern uint32_t gRestartMode;
221 extern void InstallSignalHandlers(const char *ProgramName);
222 
223 #define FILE_COMPATIBILITY_INFO NS_LITERAL_CSTRING("compatibility.ini")
224 #define FILE_INVALIDATE_CACHES NS_LITERAL_CSTRING(".purgecaches")
225 
226 int    gArgc;
227 char **gArgv;
228 
229 static const char gToolkitVersion[] = NS_STRINGIFY(GRE_MILESTONE);
230 static const char gToolkitBuildID[] = NS_STRINGIFY(MOZ_BUILDID);
231 
232 static nsIProfileLock* gProfileLock;
233 
234 int    gRestartArgc;
235 char **gRestartArgv;
236 
237 bool gIsGtest = false;
238 
239 nsString gAbsoluteArgv0Path;
240 
241 #if defined(MOZ_WIDGET_GTK)
242 #include <glib.h>
243 #if defined(DEBUG) || defined(NS_BUILD_REFCNT_LOGGING)
244 #define CLEANUP_MEMORY 1
245 #define PANGO_ENABLE_BACKEND
246 #include <pango/pangofc-fontmap.h>
247 #endif
248 #include <gtk/gtk.h>
249 #ifdef MOZ_X11
250 #include <gdk/gdkx.h>
251 #endif /* MOZ_X11 */
252 #include "nsGTKToolkit.h"
253 #include <fontconfig/fontconfig.h>
254 #endif
255 #include "BinaryPath.h"
256 #ifndef MOZ_BUILDID
257 // See comment in Makefile.in why we want to avoid including buildid.h.
258 // Still include it when MOZ_BUILDID is not set, which can happen with some
259 // build backends.
260 #include "buildid.h"
261 #endif
262 
263 #ifdef MOZ_LINKER
264 extern "C" MFBT_API bool IsSignalHandlingBroken();
265 #endif
266 
267 #ifdef LIBFUZZER
268 #include "LibFuzzerRunner.h"
269 
270 namespace mozilla {
271 LibFuzzerRunner* libFuzzerRunner = 0;
272 } // namespace mozilla
273 
XRE_LibFuzzerSetMain(int argc,char ** argv,LibFuzzerMain main)274 extern "C" MOZ_EXPORT void XRE_LibFuzzerSetMain(int argc, char** argv, LibFuzzerMain main) {
275   mozilla::libFuzzerRunner->setParams(argc, argv, main);
276 }
277 #endif
278 
279 namespace mozilla {
280 int (*RunGTest)() = 0;
281 } // namespace mozilla
282 
283 using namespace mozilla;
284 using mozilla::Unused;
285 using mozilla::scache::StartupCache;
286 using mozilla::dom::ContentParent;
287 using mozilla::dom::ContentChild;
288 
289 // Save literal putenv string to environment variable.
290 static void
SaveToEnv(const char * putenv)291 SaveToEnv(const char *putenv)
292 {
293   char *expr = strdup(putenv);
294   if (expr)
295     PR_SetEnv(expr);
296   // We intentionally leak |expr| here since it is required by PR_SetEnv.
297   MOZ_LSAN_INTENTIONALLY_LEAK_OBJECT(expr);
298 }
299 
300 // Tests that an environment variable exists and has a value
301 static bool
EnvHasValue(const char * name)302 EnvHasValue(const char *name)
303 {
304   const char *val = PR_GetEnv(name);
305   return (val && *val);
306 }
307 
308 // Save the given word to the specified environment variable.
309 static void
SaveWordToEnv(const char * name,const nsACString & word)310 SaveWordToEnv(const char *name, const nsACString & word)
311 {
312   char *expr = PR_smprintf("%s=%s", name, PromiseFlatCString(word).get());
313   if (expr)
314     PR_SetEnv(expr);
315   // We intentionally leak |expr| here since it is required by PR_SetEnv.
316 }
317 
318 // Save the path of the given file to the specified environment variable.
319 static void
SaveFileToEnv(const char * name,nsIFile * file)320 SaveFileToEnv(const char *name, nsIFile *file)
321 {
322 #ifdef XP_WIN
323   nsAutoString path;
324   file->GetPath(path);
325   SetEnvironmentVariableW(NS_ConvertASCIItoUTF16(name).get(), path.get());
326 #else
327   nsAutoCString path;
328   file->GetNativePath(path);
329   SaveWordToEnv(name, path);
330 #endif
331 }
332 
333 // Load the path of a file saved with SaveFileToEnv
334 static already_AddRefed<nsIFile>
GetFileFromEnv(const char * name)335 GetFileFromEnv(const char *name)
336 {
337   nsresult rv;
338   nsCOMPtr<nsIFile> file;
339 
340 #ifdef XP_WIN
341   WCHAR path[_MAX_PATH];
342   if (!GetEnvironmentVariableW(NS_ConvertASCIItoUTF16(name).get(),
343                                path, _MAX_PATH))
344     return nullptr;
345 
346   rv = NS_NewLocalFile(nsDependentString(path), true, getter_AddRefs(file));
347   if (NS_FAILED(rv))
348     return nullptr;
349 
350   return file.forget();
351 #else
352   const char *arg = PR_GetEnv(name);
353   if (!arg || !*arg)
354     return nullptr;
355 
356   rv = NS_NewNativeLocalFile(nsDependentCString(arg), true,
357                              getter_AddRefs(file));
358   if (NS_FAILED(rv))
359     return nullptr;
360 
361   return file.forget();
362 #endif
363 }
364 
365 // Save the path of the given word to the specified environment variable
366 // provided the environment variable does not have a value.
367 static void
SaveWordToEnvIfUnset(const char * name,const nsACString & word)368 SaveWordToEnvIfUnset(const char *name, const nsACString & word)
369 {
370   if (!EnvHasValue(name))
371     SaveWordToEnv(name, word);
372 }
373 
374 // Save the path of the given file to the specified environment variable
375 // provided the environment variable does not have a value.
376 static void
SaveFileToEnvIfUnset(const char * name,nsIFile * file)377 SaveFileToEnvIfUnset(const char *name, nsIFile *file)
378 {
379   if (!EnvHasValue(name))
380     SaveFileToEnv(name, file);
381 }
382 
383 static bool
strimatch(const char * lowerstr,const char * mixedstr)384 strimatch(const char* lowerstr, const char* mixedstr)
385 {
386   while(*lowerstr) {
387     if (!*mixedstr) return false; // mixedstr is shorter
388     if (tolower(*mixedstr) != *lowerstr) return false; // no match
389 
390     ++lowerstr;
391     ++mixedstr;
392   }
393 
394   if (*mixedstr) return false; // lowerstr is shorter
395 
396   return true;
397 }
398 
399 static bool gIsExpectedExit = false;
400 
MozExpectedExit()401 void MozExpectedExit() {
402   gIsExpectedExit = true;
403 }
404 
405 /**
406  * Runs atexit() to catch unexpected exit from 3rd party libraries like the
407  * Intel graphics driver calling exit in an error condition. When they
408  * call exit() to report an error we won't shutdown correctly and wont catch
409  * the issue with our crash reporter.
410  */
UnexpectedExit()411 static void UnexpectedExit() {
412   if (!gIsExpectedExit) {
413     gIsExpectedExit = true; // Don't risk re-entrency issues when crashing.
414     MOZ_CRASH("Exit called by third party code.");
415   }
416 }
417 
418 /**
419  * Output a string to the user.  This method is really only meant to be used to
420  * output last-ditch error messages designed for developers NOT END USERS.
421  *
422  * @param isError
423  *        Pass true to indicate severe errors.
424  * @param fmt
425  *        printf-style format string followed by arguments.
426  */
Output(bool isError,const char * fmt,...)427 static void Output(bool isError, const char *fmt, ... )
428 {
429   va_list ap;
430   va_start(ap, fmt);
431 
432 #if defined(XP_WIN) && !MOZ_WINCONSOLE
433   char *msg = PR_vsmprintf(fmt, ap);
434   if (msg)
435   {
436     UINT flags = MB_OK;
437     if (isError)
438       flags |= MB_ICONERROR;
439     else
440       flags |= MB_ICONINFORMATION;
441 
442     wchar_t wide_msg[1024];
443     MultiByteToWideChar(CP_ACP,
444                         0,
445                         msg,
446                         -1,
447                         wide_msg,
448                         sizeof(wide_msg) / sizeof(wchar_t));
449 
450     MessageBoxW(nullptr, wide_msg, L"XULRunner", flags);
451     PR_smprintf_free(msg);
452   }
453 #else
454   vfprintf(stderr, fmt, ap);
455 #endif
456 
457   va_end(ap);
458 }
459 
460 enum RemoteResult {
461   REMOTE_NOT_FOUND  = 0,
462   REMOTE_FOUND      = 1,
463   REMOTE_ARG_BAD    = 2
464 };
465 
466 enum ArgResult {
467   ARG_NONE  = 0,
468   ARG_FOUND = 1,
469   ARG_BAD   = 2 // you wanted a param, but there isn't one
470 };
471 
RemoveArg(char ** argv)472 static void RemoveArg(char **argv)
473 {
474   do {
475     *argv = *(argv + 1);
476     ++argv;
477   } while (*argv);
478 
479   --gArgc;
480 }
481 
482 /**
483  * Check for a commandline flag. If the flag takes a parameter, the
484  * parameter is returned in aParam. Flags may be in the form -arg or
485  * --arg (or /arg on win32).
486  *
487  * @param aArg the parameter to check. Must be lowercase.
488  * @param aCheckOSInt if true returns ARG_BAD if the osint argument is present
489  *        when aArg is also present.
490  * @param aParam if non-null, the -arg <data> will be stored in this pointer.
491  *        This is *not* allocated, but rather a pointer to the argv data.
492  * @param aRemArg if true, the argument is removed from the gArgv array.
493  */
494 static ArgResult
CheckArg(const char * aArg,bool aCheckOSInt=false,const char ** aParam=nullptr,bool aRemArg=true)495 CheckArg(const char* aArg, bool aCheckOSInt = false, const char **aParam = nullptr, bool aRemArg = true)
496 {
497   MOZ_ASSERT(gArgv, "gArgv must be initialized before CheckArg()");
498 
499   char **curarg = gArgv + 1; // skip argv[0]
500   ArgResult ar = ARG_NONE;
501 
502   while (*curarg) {
503     char *arg = curarg[0];
504 
505     if (arg[0] == '-'
506 #if defined(XP_WIN)
507         || *arg == '/'
508 #endif
509         ) {
510       ++arg;
511       if (*arg == '-')
512         ++arg;
513 
514       if (strimatch(aArg, arg)) {
515         if (aRemArg)
516           RemoveArg(curarg);
517         else
518           ++curarg;
519         if (!aParam) {
520           ar = ARG_FOUND;
521           break;
522         }
523 
524         if (*curarg) {
525           if (**curarg == '-'
526 #if defined(XP_WIN)
527               || **curarg == '/'
528 #endif
529               )
530             return ARG_BAD;
531 
532           *aParam = *curarg;
533           if (aRemArg)
534             RemoveArg(curarg);
535           ar = ARG_FOUND;
536           break;
537         }
538         return ARG_BAD;
539       }
540     }
541 
542     ++curarg;
543   }
544 
545   if (aCheckOSInt && ar == ARG_FOUND) {
546     ArgResult arOSInt = CheckArg("osint");
547     if (arOSInt == ARG_FOUND) {
548       ar = ARG_BAD;
549       PR_fprintf(PR_STDERR, "Error: argument --osint is invalid\n");
550     }
551   }
552 
553   return ar;
554 }
555 
556 #if defined(XP_WIN)
557 /**
558  * Check for a commandline flag from the windows shell and remove it from the
559  * argv used when restarting. Flags MUST be in the form -arg.
560  *
561  * @param aArg the parameter to check. Must be lowercase.
562  */
563 static ArgResult
CheckArgShell(const char * aArg)564 CheckArgShell(const char* aArg)
565 {
566   char **curarg = gRestartArgv + 1; // skip argv[0]
567 
568   while (*curarg) {
569     char *arg = curarg[0];
570 
571     if (arg[0] == '-') {
572       ++arg;
573 
574       if (strimatch(aArg, arg)) {
575         do {
576           *curarg = *(curarg + 1);
577           ++curarg;
578         } while (*curarg);
579 
580         --gRestartArgc;
581 
582         return ARG_FOUND;
583       }
584     }
585 
586     ++curarg;
587   }
588 
589   return ARG_NONE;
590 }
591 
592 /**
593  * Enabled Native App Support to process DDE messages when the app needs to
594  * restart and the app has been launched by the Windows shell to open an url.
595  * When aWait is false this will process the DDE events manually. This prevents
596  * Windows from displaying an error message due to the DDE message not being
597  * acknowledged.
598  */
599 static void
ProcessDDE(nsINativeAppSupport * aNative,bool aWait)600 ProcessDDE(nsINativeAppSupport* aNative, bool aWait)
601 {
602   // When the app is launched by the windows shell the windows shell
603   // expects the app to be available for DDE messages and if it isn't
604   // windows displays an error dialog. To prevent the error the DDE server
605   // is enabled and pending events are processed when the app needs to
606   // restart after it was launched by the shell with the requestpending
607   // argument. The requestpending pending argument is removed to
608   // differentiate it from being launched when an app restart is not
609   // required.
610   ArgResult ar;
611   ar = CheckArgShell("requestpending");
612   if (ar == ARG_FOUND) {
613     aNative->Enable(); // enable win32 DDE responses
614     if (aWait) {
615       nsIThread *thread = NS_GetCurrentThread();
616       // This is just a guesstimate based on testing different values.
617       // If count is 8 or less windows will display an error dialog.
618       int32_t count = 20;
619       while(--count >= 0) {
620         NS_ProcessNextEvent(thread);
621         PR_Sleep(PR_MillisecondsToInterval(1));
622       }
623     }
624   }
625 }
626 #endif
627 
628 /**
629  * Determines if there is support for showing the profile manager
630  *
631  * @return true in all environments
632 */
633 static bool
CanShowProfileManager()634 CanShowProfileManager()
635 {
636   return true;
637 }
638 
639 bool gSafeMode = false;
640 
641 /**
642  * The nsXULAppInfo object implements nsIFactory so that it can be its own
643  * singleton.
644  */
645 class nsXULAppInfo : public nsIXULAppInfo,
646                      public nsIObserver,
647 #ifdef XP_WIN
648                      public nsIWinAppHelper,
649 #endif
650 #ifdef MOZ_CRASHREPORTER
651                      public nsICrashReporter,
652                      public nsIFinishDumpingCallback,
653 #endif
654                      public nsIXULRuntime
655 
656 {
657 public:
nsXULAppInfo()658   constexpr nsXULAppInfo() {}
659   NS_DECL_ISUPPORTS_INHERITED
660   NS_DECL_NSIPLATFORMINFO
661   NS_DECL_NSIXULAPPINFO
662   NS_DECL_NSIXULRUNTIME
663   NS_DECL_NSIOBSERVER
664 #ifdef MOZ_CRASHREPORTER
665   NS_DECL_NSICRASHREPORTER
666   NS_DECL_NSIFINISHDUMPINGCALLBACK
667 #endif
668 #ifdef XP_WIN
669   NS_DECL_NSIWINAPPHELPER
670 #endif
671 };
672 
673 NS_INTERFACE_MAP_BEGIN(nsXULAppInfo)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports,nsIXULRuntime)674   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXULRuntime)
675   NS_INTERFACE_MAP_ENTRY(nsIXULRuntime)
676   NS_INTERFACE_MAP_ENTRY(nsIObserver)
677 #ifdef XP_WIN
678   NS_INTERFACE_MAP_ENTRY(nsIWinAppHelper)
679 #endif
680 #ifdef MOZ_CRASHREPORTER
681   NS_INTERFACE_MAP_ENTRY(nsICrashReporter)
682   NS_INTERFACE_MAP_ENTRY(nsIFinishDumpingCallback)
683 #endif
684   NS_INTERFACE_MAP_ENTRY(nsIPlatformInfo)
685   NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIXULAppInfo, gAppData ||
686                                      XRE_IsContentProcess())
687 NS_INTERFACE_MAP_END
688 
689 NS_IMETHODIMP_(MozExternalRefCountType)
690 nsXULAppInfo::AddRef()
691 {
692   return 1;
693 }
694 
NS_IMETHODIMP_(MozExternalRefCountType)695 NS_IMETHODIMP_(MozExternalRefCountType)
696 nsXULAppInfo::Release()
697 {
698   return 1;
699 }
700 
701 NS_IMETHODIMP
GetVendor(nsACString & aResult)702 nsXULAppInfo::GetVendor(nsACString& aResult)
703 {
704   if (XRE_IsContentProcess()) {
705     ContentChild* cc = ContentChild::GetSingleton();
706     aResult = cc->GetAppInfo().vendor;
707     return NS_OK;
708   }
709   aResult.Assign(gAppData->vendor);
710 
711   return NS_OK;
712 }
713 
714 NS_IMETHODIMP
GetName(nsACString & aResult)715 nsXULAppInfo::GetName(nsACString& aResult)
716 {
717   if (XRE_IsContentProcess()) {
718     ContentChild* cc = ContentChild::GetSingleton();
719     aResult = cc->GetAppInfo().name;
720     return NS_OK;
721   }
722   aResult.Assign(gAppData->name);
723 
724   return NS_OK;
725 }
726 
727 NS_IMETHODIMP
GetID(nsACString & aResult)728 nsXULAppInfo::GetID(nsACString& aResult)
729 {
730   if (XRE_IsContentProcess()) {
731     ContentChild* cc = ContentChild::GetSingleton();
732     aResult = cc->GetAppInfo().ID;
733     return NS_OK;
734   }
735   aResult.Assign(gAppData->ID);
736 
737   return NS_OK;
738 }
739 
740 NS_IMETHODIMP
GetVersion(nsACString & aResult)741 nsXULAppInfo::GetVersion(nsACString& aResult)
742 {
743   if (XRE_IsContentProcess()) {
744     ContentChild* cc = ContentChild::GetSingleton();
745     aResult = cc->GetAppInfo().version;
746     return NS_OK;
747   }
748   aResult.Assign(gAppData->version);
749 
750   return NS_OK;
751 }
752 
753 NS_IMETHODIMP
GetPlatformVersion(nsACString & aResult)754 nsXULAppInfo::GetPlatformVersion(nsACString& aResult)
755 {
756   aResult.Assign(gToolkitVersion);
757 
758   return NS_OK;
759 }
760 
761 NS_IMETHODIMP
GetAppBuildID(nsACString & aResult)762 nsXULAppInfo::GetAppBuildID(nsACString& aResult)
763 {
764   if (XRE_IsContentProcess()) {
765     ContentChild* cc = ContentChild::GetSingleton();
766     aResult = cc->GetAppInfo().buildID;
767     return NS_OK;
768   }
769   aResult.Assign(gAppData->buildID);
770 
771   return NS_OK;
772 }
773 
774 NS_IMETHODIMP
GetPlatformBuildID(nsACString & aResult)775 nsXULAppInfo::GetPlatformBuildID(nsACString& aResult)
776 {
777   aResult.Assign(gToolkitBuildID);
778 
779   return NS_OK;
780 }
781 
782 NS_IMETHODIMP
GetUAName(nsACString & aResult)783 nsXULAppInfo::GetUAName(nsACString& aResult)
784 {
785   if (XRE_IsContentProcess()) {
786     ContentChild* cc = ContentChild::GetSingleton();
787     aResult = cc->GetAppInfo().UAName;
788     return NS_OK;
789   }
790   aResult.Assign(gAppData->UAName);
791 
792   return NS_OK;
793 }
794 
795 NS_IMETHODIMP
GetLogConsoleErrors(bool * aResult)796 nsXULAppInfo::GetLogConsoleErrors(bool *aResult)
797 {
798   *aResult = gLogConsoleErrors;
799   return NS_OK;
800 }
801 
802 NS_IMETHODIMP
SetLogConsoleErrors(bool aValue)803 nsXULAppInfo::SetLogConsoleErrors(bool aValue)
804 {
805   gLogConsoleErrors = aValue;
806   return NS_OK;
807 }
808 
809 NS_IMETHODIMP
GetInSafeMode(bool * aResult)810 nsXULAppInfo::GetInSafeMode(bool *aResult)
811 {
812   *aResult = gSafeMode;
813   return NS_OK;
814 }
815 
816 NS_IMETHODIMP
GetOS(nsACString & aResult)817 nsXULAppInfo::GetOS(nsACString& aResult)
818 {
819   aResult.AssignLiteral(OS_TARGET);
820   return NS_OK;
821 }
822 
823 NS_IMETHODIMP
GetXPCOMABI(nsACString & aResult)824 nsXULAppInfo::GetXPCOMABI(nsACString& aResult)
825 {
826 #ifdef TARGET_XPCOM_ABI
827   aResult.AssignLiteral(TARGET_XPCOM_ABI);
828   return NS_OK;
829 #else
830   return NS_ERROR_NOT_AVAILABLE;
831 #endif
832 }
833 
834 NS_IMETHODIMP
GetWidgetToolkit(nsACString & aResult)835 nsXULAppInfo::GetWidgetToolkit(nsACString& aResult)
836 {
837   aResult.AssignLiteral(MOZ_WIDGET_TOOLKIT);
838   return NS_OK;
839 }
840 
841 // Ensure that the GeckoProcessType enum, defined in xpcom/build/nsXULAppAPI.h,
842 // is synchronized with the const unsigned longs defined in
843 // xpcom/system/nsIXULRuntime.idl.
844 #define SYNC_ENUMS(a,b) \
845   static_assert(nsIXULRuntime::PROCESS_TYPE_ ## a == \
846                 static_cast<int>(GeckoProcessType_ ## b), \
847                 "GeckoProcessType in nsXULAppAPI.h not synchronized with nsIXULRuntime.idl");
848 
849 SYNC_ENUMS(DEFAULT, Default)
850 SYNC_ENUMS(PLUGIN, Plugin)
851 SYNC_ENUMS(CONTENT, Content)
852 SYNC_ENUMS(IPDLUNITTEST, IPDLUnitTest)
853 SYNC_ENUMS(GMPLUGIN, GMPlugin)
854 SYNC_ENUMS(GPU, GPU)
855 
856 // .. and ensure that that is all of them:
857 static_assert(GeckoProcessType_GPU + 1 == GeckoProcessType_End,
858               "Did not find the final GeckoProcessType");
859 
860 NS_IMETHODIMP
GetProcessType(uint32_t * aResult)861 nsXULAppInfo::GetProcessType(uint32_t* aResult)
862 {
863   NS_ENSURE_ARG_POINTER(aResult);
864   *aResult = XRE_GetProcessType();
865   return NS_OK;
866 }
867 
868 NS_IMETHODIMP
GetProcessID(uint32_t * aResult)869 nsXULAppInfo::GetProcessID(uint32_t* aResult)
870 {
871 #ifdef XP_WIN
872   *aResult = GetCurrentProcessId();
873 #else
874   *aResult = getpid();
875 #endif
876   return NS_OK;
877 }
878 
879 NS_IMETHODIMP
GetUniqueProcessID(uint64_t * aResult)880 nsXULAppInfo::GetUniqueProcessID(uint64_t* aResult)
881 {
882   if (XRE_IsContentProcess()) {
883     ContentChild* cc = ContentChild::GetSingleton();
884     *aResult = cc->GetID();
885   } else {
886     *aResult = 0;
887   }
888   return NS_OK;
889 }
890 
891 static bool gBrowserTabsRemoteAutostart = false;
892 static uint64_t gBrowserTabsRemoteStatus = 0;
893 static bool gBrowserTabsRemoteAutostartInitialized = false;
894 
895 static bool gMultiprocessBlockPolicyInitialized = false;
896 static uint32_t gMultiprocessBlockPolicy = 0;
897 
898 NS_IMETHODIMP
Observe(nsISupports * aSubject,const char * aTopic,const char16_t * aData)899 nsXULAppInfo::Observe(nsISupports *aSubject, const char *aTopic, const char16_t *aData) {
900   if (!nsCRT::strcmp(aTopic, "getE10SBlocked")) {
901     nsCOMPtr<nsISupportsPRUint64> ret = do_QueryInterface(aSubject);
902     if (!ret)
903       return NS_ERROR_FAILURE;
904 
905     ret->SetData(gBrowserTabsRemoteStatus);
906 
907     return NS_OK;
908   }
909   return NS_ERROR_FAILURE;
910 }
911 
912 NS_IMETHODIMP
GetBrowserTabsRemoteAutostart(bool * aResult)913 nsXULAppInfo::GetBrowserTabsRemoteAutostart(bool* aResult)
914 {
915   *aResult = BrowserTabsRemoteAutostart();
916   return NS_OK;
917 }
918 
919 NS_IMETHODIMP
GetMultiprocessBlockPolicy(uint32_t * aResult)920 nsXULAppInfo::GetMultiprocessBlockPolicy(uint32_t* aResult)
921 {
922   *aResult = MultiprocessBlockPolicy();
923   return NS_OK;
924 }
925 
926 NS_IMETHODIMP
GetAccessibilityEnabled(bool * aResult)927 nsXULAppInfo::GetAccessibilityEnabled(bool* aResult)
928 {
929 #ifdef ACCESSIBILITY
930   *aResult = GetAccService() != nullptr;
931 #else
932   *aResult = false;
933 #endif
934   return NS_OK;
935 }
936 
937 NS_IMETHODIMP
GetIs64Bit(bool * aResult)938 nsXULAppInfo::GetIs64Bit(bool* aResult)
939 {
940 #ifdef HAVE_64BIT_BUILD
941   *aResult = true;
942 #else
943   *aResult = false;
944 #endif
945   return NS_OK;
946 }
947 
948 NS_IMETHODIMP
EnsureContentProcess()949 nsXULAppInfo::EnsureContentProcess()
950 {
951   if (!XRE_IsParentProcess())
952     return NS_ERROR_NOT_AVAILABLE;
953 
954   RefPtr<ContentParent> unused = ContentParent::GetNewOrUsedBrowserProcess();
955   return NS_OK;
956 }
957 
958 NS_IMETHODIMP
InvalidateCachesOnRestart()959 nsXULAppInfo::InvalidateCachesOnRestart()
960 {
961   nsCOMPtr<nsIFile> file;
962   nsresult rv = NS_GetSpecialDirectory(NS_APP_PROFILE_DIR_STARTUP,
963                                        getter_AddRefs(file));
964   if (NS_FAILED(rv))
965     return rv;
966   if (!file)
967     return NS_ERROR_NOT_AVAILABLE;
968 
969   file->AppendNative(FILE_COMPATIBILITY_INFO);
970 
971   nsINIParser parser;
972   rv = parser.Init(file);
973   if (NS_FAILED(rv)) {
974     // This fails if compatibility.ini is not there, so we'll
975     // flush the caches on the next restart anyways.
976     return NS_OK;
977   }
978 
979   nsAutoCString buf;
980   rv = parser.GetString("Compatibility", "InvalidateCaches", buf);
981 
982   if (NS_FAILED(rv)) {
983     PRFileDesc *fd;
984     rv = file->OpenNSPRFileDesc(PR_RDWR | PR_APPEND, 0600, &fd);
985     if (NS_FAILED(rv)) {
986       NS_ERROR("could not create output stream");
987       return NS_ERROR_NOT_AVAILABLE;
988     }
989     static const char kInvalidationHeader[] = NS_LINEBREAK "InvalidateCaches=1" NS_LINEBREAK;
990     PR_Write(fd, kInvalidationHeader, sizeof(kInvalidationHeader) - 1);
991     PR_Close(fd);
992   }
993   return NS_OK;
994 }
995 
996 NS_IMETHODIMP
GetReplacedLockTime(PRTime * aReplacedLockTime)997 nsXULAppInfo::GetReplacedLockTime(PRTime *aReplacedLockTime)
998 {
999   if (!gProfileLock)
1000     return NS_ERROR_NOT_AVAILABLE;
1001   gProfileLock->GetReplacedLockTime(aReplacedLockTime);
1002   return NS_OK;
1003 }
1004 
1005 NS_IMETHODIMP
GetLastRunCrashID(nsAString & aLastRunCrashID)1006 nsXULAppInfo::GetLastRunCrashID(nsAString &aLastRunCrashID)
1007 {
1008 #ifdef MOZ_CRASHREPORTER
1009   CrashReporter::GetLastRunCrashID(aLastRunCrashID);
1010   return NS_OK;
1011 #else
1012   return NS_ERROR_NOT_IMPLEMENTED;
1013 #endif
1014 }
1015 
1016 NS_IMETHODIMP
GetIsReleaseOrBeta(bool * aResult)1017 nsXULAppInfo::GetIsReleaseOrBeta(bool* aResult)
1018 {
1019 #ifdef RELEASE_OR_BETA
1020   *aResult = true;
1021 #else
1022   *aResult = false;
1023 #endif
1024   return NS_OK;
1025 }
1026 
1027 NS_IMETHODIMP
GetIsOfficialBranding(bool * aResult)1028 nsXULAppInfo::GetIsOfficialBranding(bool* aResult)
1029 {
1030 #ifdef MOZ_OFFICIAL_BRANDING
1031   *aResult = true;
1032 #else
1033   *aResult = false;
1034 #endif
1035   return NS_OK;
1036 }
1037 
1038 NS_IMETHODIMP
GetDefaultUpdateChannel(nsACString & aResult)1039 nsXULAppInfo::GetDefaultUpdateChannel(nsACString& aResult)
1040 {
1041   aResult.AssignLiteral(NS_STRINGIFY(MOZ_UPDATE_CHANNEL));
1042   return NS_OK;
1043 }
1044 
1045 NS_IMETHODIMP
GetDistributionID(nsACString & aResult)1046 nsXULAppInfo::GetDistributionID(nsACString& aResult)
1047 {
1048   aResult.AssignLiteral(MOZ_DISTRIBUTION_ID);
1049   return NS_OK;
1050 }
1051 
1052 NS_IMETHODIMP
GetIsOfficial(bool * aResult)1053 nsXULAppInfo::GetIsOfficial(bool* aResult)
1054 {
1055 #ifdef MOZILLA_OFFICIAL
1056   *aResult = true;
1057 #else
1058   *aResult = false;
1059 #endif
1060   return NS_OK;
1061 }
1062 
1063 NS_IMETHODIMP
GetWindowsDLLBlocklistStatus(bool * aResult)1064 nsXULAppInfo::GetWindowsDLLBlocklistStatus(bool* aResult)
1065 {
1066 #if defined(XP_WIN)
1067   *aResult = gAppData->flags & NS_XRE_DLL_BLOCKLIST_ENABLED;
1068 #else
1069   *aResult = false;
1070 #endif
1071   return NS_OK;
1072 }
1073 
1074 #ifdef XP_WIN
1075 // Matches the enum in WinNT.h for the Vista SDK but renamed so that we can
1076 // safely build with the Vista SDK and without it.
1077 typedef enum
1078 {
1079   VistaTokenElevationTypeDefault = 1,
1080   VistaTokenElevationTypeFull,
1081   VistaTokenElevationTypeLimited
1082 } VISTA_TOKEN_ELEVATION_TYPE;
1083 
1084 // avoid collision with TokeElevationType enum in WinNT.h
1085 // of the Vista SDK
1086 #define VistaTokenElevationType static_cast< TOKEN_INFORMATION_CLASS >( 18 )
1087 
1088 NS_IMETHODIMP
GetUserCanElevate(bool * aUserCanElevate)1089 nsXULAppInfo::GetUserCanElevate(bool *aUserCanElevate)
1090 {
1091   HANDLE hToken;
1092 
1093   VISTA_TOKEN_ELEVATION_TYPE elevationType;
1094   DWORD dwSize;
1095 
1096   if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken) ||
1097       !GetTokenInformation(hToken, VistaTokenElevationType, &elevationType,
1098                            sizeof(elevationType), &dwSize)) {
1099     *aUserCanElevate = false;
1100   }
1101   else {
1102     // The possible values returned for elevationType and their meanings are:
1103     //   TokenElevationTypeDefault: The token does not have a linked token
1104     //     (e.g. UAC disabled or a standard user, so they can't be elevated)
1105     //   TokenElevationTypeFull: The token is linked to an elevated token
1106     //     (e.g. UAC is enabled and the user is already elevated so they can't
1107     //      be elevated again)
1108     //   TokenElevationTypeLimited: The token is linked to a limited token
1109     //     (e.g. UAC is enabled and the user is not elevated, so they can be
1110     //      elevated)
1111     *aUserCanElevate = (elevationType == VistaTokenElevationTypeLimited);
1112   }
1113 
1114   if (hToken)
1115     CloseHandle(hToken);
1116 
1117   return NS_OK;
1118 }
1119 #endif
1120 
1121 #ifdef MOZ_CRASHREPORTER
1122 NS_IMETHODIMP
GetEnabled(bool * aEnabled)1123 nsXULAppInfo::GetEnabled(bool *aEnabled)
1124 {
1125   *aEnabled = CrashReporter::GetEnabled();
1126   return NS_OK;
1127 }
1128 
1129 NS_IMETHODIMP
SetEnabled(bool aEnabled)1130 nsXULAppInfo::SetEnabled(bool aEnabled)
1131 {
1132   if (aEnabled) {
1133     if (CrashReporter::GetEnabled()) {
1134       // no point in erroring for double-enabling
1135       return NS_OK;
1136     }
1137 
1138     nsCOMPtr<nsIFile> greBinDir;
1139     NS_GetSpecialDirectory(NS_GRE_BIN_DIR, getter_AddRefs(greBinDir));
1140     if (!greBinDir) {
1141       return NS_ERROR_FAILURE;
1142     }
1143 
1144     nsCOMPtr<nsIFile> xreBinDirectory = do_QueryInterface(greBinDir);
1145     if (!xreBinDirectory) {
1146       return NS_ERROR_FAILURE;
1147     }
1148 
1149     return CrashReporter::SetExceptionHandler(xreBinDirectory, true);
1150   }
1151   else {
1152     if (!CrashReporter::GetEnabled()) {
1153       // no point in erroring for double-disabling
1154       return NS_OK;
1155     }
1156 
1157     return CrashReporter::UnsetExceptionHandler();
1158   }
1159 }
1160 
1161 NS_IMETHODIMP
GetServerURL(nsIURL ** aServerURL)1162 nsXULAppInfo::GetServerURL(nsIURL** aServerURL)
1163 {
1164   if (!CrashReporter::GetEnabled())
1165     return NS_ERROR_NOT_INITIALIZED;
1166 
1167   nsAutoCString data;
1168   if (!CrashReporter::GetServerURL(data)) {
1169     return NS_ERROR_FAILURE;
1170   }
1171   nsCOMPtr<nsIURI> uri;
1172   NS_NewURI(getter_AddRefs(uri), data);
1173   if (!uri)
1174     return NS_ERROR_FAILURE;
1175 
1176   nsCOMPtr<nsIURL> url;
1177   url = do_QueryInterface(uri);
1178   NS_ADDREF(*aServerURL = url);
1179 
1180   return NS_OK;
1181 }
1182 
1183 NS_IMETHODIMP
SetServerURL(nsIURL * aServerURL)1184 nsXULAppInfo::SetServerURL(nsIURL* aServerURL)
1185 {
1186   bool schemeOk;
1187   // only allow https or http URLs
1188   nsresult rv = aServerURL->SchemeIs("https", &schemeOk);
1189   NS_ENSURE_SUCCESS(rv, rv);
1190   if (!schemeOk) {
1191     rv = aServerURL->SchemeIs("http", &schemeOk);
1192     NS_ENSURE_SUCCESS(rv, rv);
1193 
1194     if (!schemeOk)
1195       return NS_ERROR_INVALID_ARG;
1196   }
1197   nsAutoCString spec;
1198   rv = aServerURL->GetSpec(spec);
1199   NS_ENSURE_SUCCESS(rv, rv);
1200 
1201   return CrashReporter::SetServerURL(spec);
1202 }
1203 
1204 NS_IMETHODIMP
GetMinidumpPath(nsIFile ** aMinidumpPath)1205 nsXULAppInfo::GetMinidumpPath(nsIFile** aMinidumpPath)
1206 {
1207   if (!CrashReporter::GetEnabled())
1208     return NS_ERROR_NOT_INITIALIZED;
1209 
1210   nsAutoString path;
1211   if (!CrashReporter::GetMinidumpPath(path))
1212     return NS_ERROR_FAILURE;
1213 
1214   nsresult rv = NS_NewLocalFile(path, false, aMinidumpPath);
1215   NS_ENSURE_SUCCESS(rv, rv);
1216   return NS_OK;
1217 }
1218 
1219 NS_IMETHODIMP
SetMinidumpPath(nsIFile * aMinidumpPath)1220 nsXULAppInfo::SetMinidumpPath(nsIFile* aMinidumpPath)
1221 {
1222   nsAutoString path;
1223   nsresult rv = aMinidumpPath->GetPath(path);
1224   NS_ENSURE_SUCCESS(rv, rv);
1225   return CrashReporter::SetMinidumpPath(path);
1226 }
1227 
1228 NS_IMETHODIMP
AnnotateCrashReport(const nsACString & key,const nsACString & data)1229 nsXULAppInfo::AnnotateCrashReport(const nsACString& key,
1230                                   const nsACString& data)
1231 {
1232   return CrashReporter::AnnotateCrashReport(key, data);
1233 }
1234 
1235 NS_IMETHODIMP
AppendAppNotesToCrashReport(const nsACString & data)1236 nsXULAppInfo::AppendAppNotesToCrashReport(const nsACString& data)
1237 {
1238   return CrashReporter::AppendAppNotesToCrashReport(data);
1239 }
1240 
1241 NS_IMETHODIMP
RegisterAppMemory(uint64_t pointer,uint64_t len)1242 nsXULAppInfo::RegisterAppMemory(uint64_t pointer,
1243                                 uint64_t len)
1244 {
1245   return CrashReporter::RegisterAppMemory((void *)pointer, len);
1246 }
1247 
1248 NS_IMETHODIMP
WriteMinidumpForException(void * aExceptionInfo)1249 nsXULAppInfo::WriteMinidumpForException(void* aExceptionInfo)
1250 {
1251 #ifdef XP_WIN32
1252   return CrashReporter::WriteMinidumpForException(static_cast<EXCEPTION_POINTERS*>(aExceptionInfo));
1253 #else
1254   return NS_ERROR_NOT_IMPLEMENTED;
1255 #endif
1256 }
1257 
1258 NS_IMETHODIMP
AppendObjCExceptionInfoToAppNotes(void * aException)1259 nsXULAppInfo::AppendObjCExceptionInfoToAppNotes(void* aException)
1260 {
1261 #ifdef XP_MACOSX
1262   return CrashReporter::AppendObjCExceptionInfoToAppNotes(aException);
1263 #else
1264   return NS_ERROR_NOT_IMPLEMENTED;
1265 #endif
1266 }
1267 
1268 NS_IMETHODIMP
GetSubmitReports(bool * aEnabled)1269 nsXULAppInfo::GetSubmitReports(bool* aEnabled)
1270 {
1271   return CrashReporter::GetSubmitReports(aEnabled);
1272 }
1273 
1274 NS_IMETHODIMP
SetSubmitReports(bool aEnabled)1275 nsXULAppInfo::SetSubmitReports(bool aEnabled)
1276 {
1277   return CrashReporter::SetSubmitReports(aEnabled);
1278 }
1279 
1280 NS_IMETHODIMP
UpdateCrashEventsDir()1281 nsXULAppInfo::UpdateCrashEventsDir()
1282 {
1283   CrashReporter::UpdateCrashEventsDir();
1284   return NS_OK;
1285 }
1286 
1287 NS_IMETHODIMP
SaveMemoryReport()1288 nsXULAppInfo::SaveMemoryReport()
1289 {
1290   if (!CrashReporter::GetEnabled()) {
1291     return NS_ERROR_NOT_INITIALIZED;
1292   }
1293   nsCOMPtr<nsIFile> file;
1294   nsresult rv = CrashReporter::GetDefaultMemoryReportFile(getter_AddRefs(file));
1295   if (NS_WARN_IF(NS_FAILED(rv))) {
1296     return rv;
1297   }
1298 
1299   nsString path;
1300   file->GetPath(path);
1301 
1302   nsCOMPtr<nsIMemoryInfoDumper> dumper =
1303     do_GetService("@mozilla.org/memory-info-dumper;1");
1304   if (NS_WARN_IF(!dumper)) {
1305     return NS_ERROR_UNEXPECTED;
1306   }
1307 
1308   rv = dumper->DumpMemoryReportsToNamedFile(path, this, file, true /* anonymize */);
1309   if (NS_WARN_IF(NS_FAILED(rv))) {
1310     return rv;
1311   }
1312   return NS_OK;
1313 }
1314 
1315 NS_IMETHODIMP
SetTelemetrySessionId(const nsACString & id)1316 nsXULAppInfo::SetTelemetrySessionId(const nsACString& id)
1317 {
1318   CrashReporter::SetTelemetrySessionId(id);
1319   return NS_OK;
1320 }
1321 
1322 // This method is from nsIFInishDumpingCallback.
1323 NS_IMETHODIMP
Callback(nsISupports * aData)1324 nsXULAppInfo::Callback(nsISupports* aData)
1325 {
1326   nsCOMPtr<nsIFile> file = do_QueryInterface(aData);
1327   MOZ_ASSERT(file);
1328 
1329   CrashReporter::SetMemoryReportFile(file);
1330   return NS_OK;
1331 }
1332 #endif
1333 
1334 static const nsXULAppInfo kAppInfo;
AppInfoConstructor(nsISupports * aOuter,REFNSIID aIID,void ** aResult)1335 static nsresult AppInfoConstructor(nsISupports* aOuter,
1336                                    REFNSIID aIID, void **aResult)
1337 {
1338   NS_ENSURE_NO_AGGREGATION(aOuter);
1339 
1340   return const_cast<nsXULAppInfo*>(&kAppInfo)->
1341     QueryInterface(aIID, aResult);
1342 }
1343 
1344 bool gLogConsoleErrors = false;
1345 
1346 #define NS_ENSURE_TRUE_LOG(x, ret)               \
1347   PR_BEGIN_MACRO                                 \
1348   if (MOZ_UNLIKELY(!(x))) {                      \
1349     NS_WARNING("NS_ENSURE_TRUE(" #x ") failed"); \
1350     gLogConsoleErrors = true;                    \
1351     return ret;                                  \
1352   }                                              \
1353   PR_END_MACRO
1354 
1355 #define NS_ENSURE_SUCCESS_LOG(res, ret)          \
1356   NS_ENSURE_TRUE_LOG(NS_SUCCEEDED(res), ret)
1357 
1358 /**
1359  * Because we're starting/stopping XPCOM several times in different scenarios,
1360  * this class is a stack-based critter that makes sure that XPCOM is shut down
1361  * during early returns.
1362  */
1363 
1364 class ScopedXPCOMStartup
1365 {
1366 public:
ScopedXPCOMStartup()1367   ScopedXPCOMStartup() :
1368     mServiceManager(nullptr) { }
1369   ~ScopedXPCOMStartup();
1370 
1371   nsresult Initialize();
1372   nsresult SetWindowCreator(nsINativeAppSupport* native);
1373 
1374   static nsresult CreateAppSupport(nsISupports* aOuter, REFNSIID aIID, void** aResult);
1375 
1376 private:
1377   nsIServiceManager* mServiceManager;
1378   static nsINativeAppSupport* gNativeAppSupport;
1379 };
1380 
~ScopedXPCOMStartup()1381 ScopedXPCOMStartup::~ScopedXPCOMStartup()
1382 {
1383   NS_IF_RELEASE(gNativeAppSupport);
1384 
1385   if (mServiceManager) {
1386 #ifdef XP_MACOSX
1387     // On OS X, we need a pool to catch cocoa objects that are autoreleased
1388     // during teardown.
1389     mozilla::MacAutoreleasePool pool;
1390 #endif
1391 
1392     nsCOMPtr<nsIAppStartup> appStartup (do_GetService(NS_APPSTARTUP_CONTRACTID));
1393     if (appStartup)
1394       appStartup->DestroyHiddenWindow();
1395 
1396     gDirServiceProvider->DoShutdown();
1397     PROFILER_MARKER("Shutdown early");
1398 
1399     WriteConsoleLog();
1400 
1401     NS_ShutdownXPCOM(mServiceManager);
1402     mServiceManager = nullptr;
1403   }
1404 }
1405 
1406 // {95d89e3e-a169-41a3-8e56-719978e15b12}
1407 #define APPINFO_CID \
1408   { 0x95d89e3e, 0xa169, 0x41a3, { 0x8e, 0x56, 0x71, 0x99, 0x78, 0xe1, 0x5b, 0x12 } }
1409 
1410 // {0C4A446C-EE82-41f2-8D04-D366D2C7A7D4}
1411 static const nsCID kNativeAppSupportCID =
1412   { 0xc4a446c, 0xee82, 0x41f2, { 0x8d, 0x4, 0xd3, 0x66, 0xd2, 0xc7, 0xa7, 0xd4 } };
1413 
1414 // {5F5E59CE-27BC-47eb-9D1F-B09CA9049836}
1415 static const nsCID kProfileServiceCID =
1416   { 0x5f5e59ce, 0x27bc, 0x47eb, { 0x9d, 0x1f, 0xb0, 0x9c, 0xa9, 0x4, 0x98, 0x36 } };
1417 
1418 static already_AddRefed<nsIFactory>
ProfileServiceFactoryConstructor(const mozilla::Module & module,const mozilla::Module::CIDEntry & entry)1419 ProfileServiceFactoryConstructor(const mozilla::Module& module, const mozilla::Module::CIDEntry& entry)
1420 {
1421   nsCOMPtr<nsIFactory> factory;
1422   NS_NewToolkitProfileFactory(getter_AddRefs(factory));
1423   return factory.forget();
1424 }
1425 
1426 NS_DEFINE_NAMED_CID(APPINFO_CID);
1427 
1428 static const mozilla::Module::CIDEntry kXRECIDs[] = {
1429   { &kAPPINFO_CID, false, nullptr, AppInfoConstructor },
1430   { &kProfileServiceCID, false, ProfileServiceFactoryConstructor, nullptr },
1431   { &kNativeAppSupportCID, false, nullptr, ScopedXPCOMStartup::CreateAppSupport },
1432   { nullptr }
1433 };
1434 
1435 static const mozilla::Module::ContractIDEntry kXREContracts[] = {
1436   { XULAPPINFO_SERVICE_CONTRACTID, &kAPPINFO_CID },
1437   { XULRUNTIME_SERVICE_CONTRACTID, &kAPPINFO_CID },
1438 #ifdef MOZ_CRASHREPORTER
1439   { NS_CRASHREPORTER_CONTRACTID, &kAPPINFO_CID },
1440 #endif
1441   { NS_PROFILESERVICE_CONTRACTID, &kProfileServiceCID },
1442   { NS_NATIVEAPPSUPPORT_CONTRACTID, &kNativeAppSupportCID },
1443   { nullptr }
1444 };
1445 
1446 static const mozilla::Module kXREModule = {
1447   mozilla::Module::kVersion,
1448   kXRECIDs,
1449   kXREContracts
1450 };
1451 
1452 NSMODULE_DEFN(Apprunner) = &kXREModule;
1453 
1454 nsresult
Initialize()1455 ScopedXPCOMStartup::Initialize()
1456 {
1457   NS_ASSERTION(gDirServiceProvider, "Should not get here!");
1458 
1459   nsresult rv;
1460 
1461   rv = NS_InitXPCOM2(&mServiceManager, gDirServiceProvider->GetAppDir(),
1462                      gDirServiceProvider);
1463   if (NS_FAILED(rv)) {
1464     NS_ERROR("Couldn't start xpcom!");
1465     mServiceManager = nullptr;
1466   }
1467   else {
1468 #ifdef DEBUG
1469     nsCOMPtr<nsIComponentRegistrar> reg =
1470       do_QueryInterface(mServiceManager);
1471     NS_ASSERTION(reg, "Service Manager doesn't QI to Registrar.");
1472 #endif
1473   }
1474 
1475   return rv;
1476 }
1477 
1478 /**
1479  * This is a little factory class that serves as a singleton-service-factory
1480  * for the nativeappsupport object.
1481  */
1482 class nsSingletonFactory final : public nsIFactory
1483 {
1484 public:
1485   NS_DECL_ISUPPORTS
1486   NS_DECL_NSIFACTORY
1487 
1488   explicit nsSingletonFactory(nsISupports* aSingleton);
1489 
1490 private:
~nsSingletonFactory()1491   ~nsSingletonFactory() { }
1492   nsCOMPtr<nsISupports> mSingleton;
1493 };
1494 
nsSingletonFactory(nsISupports * aSingleton)1495 nsSingletonFactory::nsSingletonFactory(nsISupports* aSingleton)
1496   : mSingleton(aSingleton)
1497 {
1498   NS_ASSERTION(mSingleton, "Singleton was null!");
1499 }
1500 
NS_IMPL_ISUPPORTS(nsSingletonFactory,nsIFactory)1501 NS_IMPL_ISUPPORTS(nsSingletonFactory, nsIFactory)
1502 
1503 NS_IMETHODIMP
1504 nsSingletonFactory::CreateInstance(nsISupports* aOuter,
1505                                    const nsIID& aIID,
1506                                    void* *aResult)
1507 {
1508   NS_ENSURE_NO_AGGREGATION(aOuter);
1509 
1510   return mSingleton->QueryInterface(aIID, aResult);
1511 }
1512 
1513 NS_IMETHODIMP
LockFactory(bool)1514 nsSingletonFactory::LockFactory(bool)
1515 {
1516   return NS_OK;
1517 }
1518 
1519 /**
1520  * Set our windowcreator on the WindowWatcher service.
1521  */
1522 nsresult
SetWindowCreator(nsINativeAppSupport * native)1523 ScopedXPCOMStartup::SetWindowCreator(nsINativeAppSupport* native)
1524 {
1525   nsresult rv;
1526 
1527   NS_IF_ADDREF(gNativeAppSupport = native);
1528 
1529   // Inform the chrome registry about OS accessibility
1530   nsCOMPtr<nsIToolkitChromeRegistry> cr =
1531     mozilla::services::GetToolkitChromeRegistryService();
1532 
1533   if (cr)
1534     cr->CheckForOSAccessibility();
1535 
1536   nsCOMPtr<nsIWindowCreator> creator (do_GetService(NS_APPSTARTUP_CONTRACTID));
1537   if (!creator) return NS_ERROR_UNEXPECTED;
1538 
1539   nsCOMPtr<nsIWindowWatcher> wwatch
1540     (do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv));
1541   NS_ENSURE_SUCCESS(rv, rv);
1542 
1543   return wwatch->SetWindowCreator(creator);
1544 }
1545 
1546 /* static */ nsresult
CreateAppSupport(nsISupports * aOuter,REFNSIID aIID,void ** aResult)1547 ScopedXPCOMStartup::CreateAppSupport(nsISupports* aOuter, REFNSIID aIID, void** aResult)
1548 {
1549   if (aOuter)
1550     return NS_ERROR_NO_AGGREGATION;
1551 
1552   if (!gNativeAppSupport)
1553     return NS_ERROR_NOT_INITIALIZED;
1554 
1555   return gNativeAppSupport->QueryInterface(aIID, aResult);
1556 }
1557 
1558 nsINativeAppSupport* ScopedXPCOMStartup::gNativeAppSupport;
1559 
DumpArbitraryHelp()1560 static void DumpArbitraryHelp()
1561 {
1562   nsresult rv;
1563 
1564   ScopedLogging log;
1565 
1566   {
1567     ScopedXPCOMStartup xpcom;
1568     xpcom.Initialize();
1569 
1570     nsCOMPtr<nsICommandLineRunner> cmdline
1571       (do_CreateInstance("@mozilla.org/toolkit/command-line;1"));
1572     if (!cmdline)
1573       return;
1574 
1575     nsCString text;
1576     rv = cmdline->GetHelpText(text);
1577     if (NS_SUCCEEDED(rv))
1578       printf("%s", text.get());
1579   }
1580 }
1581 
1582 // English text needs to go into a dtd file.
1583 // But when this is called we have no components etc. These strings must either be
1584 // here, or in a native resource file.
1585 static void
DumpHelp()1586 DumpHelp()
1587 {
1588   printf("Usage: %s [ options ... ] [URL]\n"
1589          "       where options include:\n\n", gArgv[0]);
1590 
1591 #ifdef MOZ_X11
1592   printf("X11 options\n"
1593          "  --display=DISPLAY  X display to use\n"
1594          "  --sync             Make X calls synchronous\n");
1595 #endif
1596 #ifdef XP_UNIX
1597   printf("  --g-fatal-warnings Make all warnings fatal\n"
1598          "\n%s options\n", gAppData->name);
1599 #endif
1600 
1601   printf("  -h or --help       Print this message.\n"
1602          "  -v or --version    Print %s version.\n"
1603          "  -P <profile>       Start with <profile>.\n"
1604          "  --profile <path>   Start with profile at <path>.\n"
1605          "  --migration        Start with migration wizard.\n"
1606          "  --ProfileManager   Start with ProfileManager.\n"
1607          "  --no-remote        Do not accept or send remote commands; implies\n"
1608          "                     --new-instance.\n"
1609          "  --new-instance     Open new instance, not a new window in running instance.\n"
1610          "  --UILocale <locale> Start with <locale> resources as UI Locale.\n"
1611          "  --safe-mode        Disables extensions and themes for this session.\n", gAppData->name);
1612 
1613 #if defined(XP_WIN)
1614   printf("  --console          Start %s with a debugging console.\n", gAppData->name);
1615 #endif
1616 
1617   // this works, but only after the components have registered.  so if you drop in a new command line handler, --help
1618   // won't not until the second run.
1619   // out of the bug, because we ship a component.reg file, it works correctly.
1620   DumpArbitraryHelp();
1621 }
1622 
1623 #if defined(DEBUG) && defined(XP_WIN)
1624 #ifdef DEBUG_warren
1625 #define _CRTDBG_MAP_ALLOC
1626 #endif
1627 // Set a CRT ReportHook function to capture and format MSCRT
1628 // warnings, errors and assertions.
1629 // See http://msdn.microsoft.com/en-US/library/74kabxyx(v=VS.80).aspx
1630 #include <stdio.h>
1631 #include <crtdbg.h>
1632 #include "mozilla/mozalloc_abort.h"
MSCRTReportHook(int aReportType,char * aMessage,int * oReturnValue)1633 static int MSCRTReportHook( int aReportType, char *aMessage, int *oReturnValue)
1634 {
1635   *oReturnValue = 0; // continue execution
1636 
1637   // Do not use fprintf or other functions which may allocate
1638   // memory from the heap which may be corrupted. Instead,
1639   // use fputs to output the leading portion of the message
1640   // and use mozalloc_abort to emit the remainder of the
1641   // message.
1642 
1643   switch(aReportType) {
1644   case 0:
1645     fputs("\nWARNING: CRT WARNING", stderr);
1646     fputs(aMessage, stderr);
1647     fputs("\n", stderr);
1648     break;
1649   case 1:
1650     fputs("\n###!!! ABORT: CRT ERROR ", stderr);
1651     mozalloc_abort(aMessage);
1652     break;
1653   case 2:
1654     fputs("\n###!!! ABORT: CRT ASSERT ", stderr);
1655     mozalloc_abort(aMessage);
1656     break;
1657   }
1658 
1659   // do not invoke the debugger
1660   return 1;
1661 }
1662 
1663 #endif
1664 
1665 static inline void
DumpVersion()1666 DumpVersion()
1667 {
1668   if (gAppData->vendor)
1669     printf("%s ", gAppData->vendor);
1670   printf("%s %s", gAppData->name, gAppData->version);
1671   if (gAppData->copyright)
1672       printf(", %s", gAppData->copyright);
1673   printf("\n");
1674 }
1675 
1676 #ifdef MOZ_ENABLE_XREMOTE
1677 static RemoteResult
ParseRemoteCommandLine(nsCString & program,const char ** profile,const char ** username)1678 ParseRemoteCommandLine(nsCString& program,
1679                        const char** profile,
1680                        const char** username)
1681 {
1682   ArgResult ar;
1683 
1684   ar = CheckArg("p", false, profile, false);
1685   if (ar == ARG_BAD) {
1686     // Leave it to the normal command line handling to handle this situation.
1687     return REMOTE_NOT_FOUND;
1688   }
1689 
1690   const char *temp = nullptr;
1691   ar = CheckArg("a", true, &temp);
1692   if (ar == ARG_BAD) {
1693     PR_fprintf(PR_STDERR, "Error: argument -a requires an application name\n");
1694     return REMOTE_ARG_BAD;
1695   } else if (ar == ARG_FOUND) {
1696     program.Assign(temp);
1697   }
1698 
1699   ar = CheckArg("u", true, username);
1700   if (ar == ARG_BAD) {
1701     PR_fprintf(PR_STDERR, "Error: argument -u requires a username\n");
1702     return REMOTE_ARG_BAD;
1703   }
1704 
1705   return REMOTE_FOUND;
1706 }
1707 
1708 static RemoteResult
StartRemoteClient(const char * aDesktopStartupID,nsCString & program,const char * profile,const char * username)1709 StartRemoteClient(const char* aDesktopStartupID,
1710                   nsCString& program,
1711                   const char* profile,
1712                   const char* username)
1713 {
1714   XRemoteClient client;
1715   nsresult rv = client.Init();
1716   if (NS_FAILED(rv))
1717     return REMOTE_NOT_FOUND;
1718 
1719   nsXPIDLCString response;
1720   bool success = false;
1721   rv = client.SendCommandLine(program.get(), username, profile,
1722                               gArgc, gArgv, aDesktopStartupID,
1723                               getter_Copies(response), &success);
1724   // did the command fail?
1725   if (!success)
1726     return REMOTE_NOT_FOUND;
1727 
1728   // The "command not parseable" error is returned when the
1729   // nsICommandLineHandler throws a NS_ERROR_ABORT.
1730   if (response.EqualsLiteral("500 command not parseable"))
1731     return REMOTE_ARG_BAD;
1732 
1733   if (NS_FAILED(rv))
1734     return REMOTE_NOT_FOUND;
1735 
1736   return REMOTE_FOUND;
1737 }
1738 #endif // MOZ_ENABLE_XREMOTE
1739 
1740 void
XRE_InitOmnijar(nsIFile * greOmni,nsIFile * appOmni)1741 XRE_InitOmnijar(nsIFile* greOmni, nsIFile* appOmni)
1742 {
1743   mozilla::Omnijar::Init(greOmni, appOmni);
1744 }
1745 
1746 nsresult
XRE_GetBinaryPath(const char * argv0,nsIFile ** aResult)1747 XRE_GetBinaryPath(const char* argv0, nsIFile* *aResult)
1748 {
1749   return mozilla::BinaryPath::GetFile(argv0, aResult);
1750 }
1751 
1752 #ifdef XP_WIN
1753 #include "nsWindowsRestart.cpp"
1754 #include <shellapi.h>
1755 
1756 typedef BOOL (WINAPI* SetProcessDEPPolicyFunc)(DWORD dwFlags);
1757 #endif
1758 
1759 // If aBlankCommandLine is true, then the application will be launched with a
1760 // blank command line instead of being launched with the same command line that
1761 // it was initially started with.
LaunchChild(nsINativeAppSupport * aNative,bool aBlankCommandLine=false)1762 static nsresult LaunchChild(nsINativeAppSupport* aNative,
1763                             bool aBlankCommandLine = false)
1764 {
1765   aNative->Quit(); // release DDE mutex, if we're holding it
1766 
1767   // Restart this process by exec'ing it into the current process
1768   // if supported by the platform.  Otherwise, use NSPR.
1769 
1770 #ifdef MOZ_JPROF
1771   // make sure JPROF doesn't think we're E10s
1772   unsetenv("JPROF_SLAVE");
1773 #endif
1774 
1775   if (aBlankCommandLine) {
1776     gRestartArgc = 1;
1777     gRestartArgv[gRestartArgc] = nullptr;
1778   }
1779 
1780   SaveToEnv("MOZ_LAUNCHED_CHILD=1");
1781 
1782 #if defined(MOZ_WIDGET_ANDROID)
1783   java::GeckoAppShell::ScheduleRestart();
1784 #else
1785 #if defined(XP_MACOSX)
1786   CommandLineServiceMac::SetupMacCommandLine(gRestartArgc, gRestartArgv, true);
1787   LaunchChildMac(gRestartArgc, gRestartArgv);
1788 #else
1789   nsCOMPtr<nsIFile> lf;
1790   nsresult rv = XRE_GetBinaryPath(gArgv[0], getter_AddRefs(lf));
1791   if (NS_FAILED(rv))
1792     return rv;
1793 
1794 #if defined(XP_WIN)
1795   nsAutoString exePath;
1796   rv = lf->GetPath(exePath);
1797   if (NS_FAILED(rv))
1798     return rv;
1799 
1800   if (!WinLaunchChild(exePath.get(), gRestartArgc, gRestartArgv))
1801     return NS_ERROR_FAILURE;
1802 
1803 #else
1804   nsAutoCString exePath;
1805   rv = lf->GetNativePath(exePath);
1806   if (NS_FAILED(rv))
1807     return rv;
1808 
1809 #if defined(XP_UNIX)
1810   if (execv(exePath.get(), gRestartArgv) == -1)
1811     return NS_ERROR_FAILURE;
1812 #else
1813   PRProcess* process = PR_CreateProcess(exePath.get(), gRestartArgv,
1814                                         nullptr, nullptr);
1815   if (!process) return NS_ERROR_FAILURE;
1816 
1817   int32_t exitCode;
1818   PRStatus failed = PR_WaitProcess(process, &exitCode);
1819   if (failed || exitCode)
1820     return NS_ERROR_FAILURE;
1821 #endif // XP_UNIX
1822 #endif // WP_WIN
1823 #endif // WP_MACOSX
1824 #endif // MOZ_WIDGET_ANDROID
1825 
1826   return NS_ERROR_LAUNCHED_CHILD_PROCESS;
1827 }
1828 
1829 static const char kProfileProperties[] =
1830   "chrome://mozapps/locale/profile/profileSelection.properties";
1831 
1832 namespace {
1833 
1834 /**
1835  * This class, instead of a raw nsresult, should be the return type of any
1836  * function called by SelectProfile that initializes XPCOM.
1837  */
1838 class ReturnAbortOnError
1839 {
1840 public:
ReturnAbortOnError(nsresult aRv)1841   MOZ_IMPLICIT ReturnAbortOnError(nsresult aRv)
1842   {
1843     mRv = ConvertRv(aRv);
1844   }
1845 
operator nsresult()1846   operator nsresult()
1847   {
1848     return mRv;
1849   }
1850 
1851 private:
1852   inline nsresult
ConvertRv(nsresult aRv)1853   ConvertRv(nsresult aRv)
1854   {
1855     if (NS_SUCCEEDED(aRv) || aRv == NS_ERROR_LAUNCHED_CHILD_PROCESS) {
1856       return aRv;
1857     }
1858     return NS_ERROR_ABORT;
1859   }
1860 
1861   nsresult mRv;
1862 };
1863 
1864 } // namespace
1865 
1866 static ReturnAbortOnError
ProfileLockedDialog(nsIFile * aProfileDir,nsIFile * aProfileLocalDir,nsIProfileUnlocker * aUnlocker,nsINativeAppSupport * aNative,nsIProfileLock ** aResult)1867 ProfileLockedDialog(nsIFile* aProfileDir, nsIFile* aProfileLocalDir,
1868                     nsIProfileUnlocker* aUnlocker,
1869                     nsINativeAppSupport* aNative, nsIProfileLock* *aResult)
1870 {
1871   nsresult rv;
1872 
1873   ScopedXPCOMStartup xpcom;
1874   rv = xpcom.Initialize();
1875   NS_ENSURE_SUCCESS(rv, rv);
1876 
1877   mozilla::Telemetry::WriteFailedProfileLock(aProfileDir);
1878 
1879   rv = xpcom.SetWindowCreator(aNative);
1880   NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
1881 
1882   { //extra scoping is needed so we release these components before xpcom shutdown
1883     nsCOMPtr<nsIStringBundleService> sbs =
1884       mozilla::services::GetStringBundleService();
1885     NS_ENSURE_TRUE(sbs, NS_ERROR_FAILURE);
1886 
1887     nsCOMPtr<nsIStringBundle> sb;
1888     sbs->CreateBundle(kProfileProperties, getter_AddRefs(sb));
1889     NS_ENSURE_TRUE_LOG(sbs, NS_ERROR_FAILURE);
1890 
1891     NS_ConvertUTF8toUTF16 appName(gAppData->name);
1892     const char16_t* params[] = {appName.get(), appName.get()};
1893 
1894     nsXPIDLString killMessage;
1895 #ifndef XP_MACOSX
1896     sb->FormatStringFromName(aUnlocker ? u"restartMessageUnlocker"
1897                                        : u"restartMessageNoUnlocker",
1898                              params, 2, getter_Copies(killMessage));
1899 #else
1900     sb->FormatStringFromName(aUnlocker ? u"restartMessageUnlockerMac"
1901                                        : u"restartMessageNoUnlockerMac",
1902                              params, 2, getter_Copies(killMessage));
1903 #endif
1904 
1905     nsXPIDLString killTitle;
1906     sb->FormatStringFromName(u"restartTitle",
1907                              params, 1, getter_Copies(killTitle));
1908 
1909     if (!killMessage || !killTitle)
1910       return NS_ERROR_FAILURE;
1911 
1912     nsCOMPtr<nsIPromptService> ps
1913       (do_GetService(NS_PROMPTSERVICE_CONTRACTID));
1914     NS_ENSURE_TRUE(ps, NS_ERROR_FAILURE);
1915 
1916     if (aUnlocker) {
1917       int32_t button;
1918 #ifdef MOZ_WIDGET_ANDROID
1919       java::GeckoAppShell::KillAnyZombies();
1920       button = 0;
1921 #else
1922       const uint32_t flags =
1923         (nsIPromptService::BUTTON_TITLE_IS_STRING *
1924          nsIPromptService::BUTTON_POS_0) +
1925         (nsIPromptService::BUTTON_TITLE_CANCEL *
1926          nsIPromptService::BUTTON_POS_1);
1927 
1928       bool checkState = false;
1929       rv = ps->ConfirmEx(nullptr, killTitle, killMessage, flags,
1930                          killTitle, nullptr, nullptr, nullptr,
1931                          &checkState, &button);
1932       NS_ENSURE_SUCCESS_LOG(rv, rv);
1933 #endif
1934 
1935       if (button == 0) {
1936         rv = aUnlocker->Unlock(nsIProfileUnlocker::FORCE_QUIT);
1937         if (NS_FAILED(rv)) {
1938           return rv;
1939         }
1940 
1941         SaveFileToEnv("XRE_PROFILE_PATH", aProfileDir);
1942         SaveFileToEnv("XRE_PROFILE_LOCAL_PATH", aProfileLocalDir);
1943 
1944         return LaunchChild(aNative);
1945       }
1946     } else {
1947 #ifdef MOZ_WIDGET_ANDROID
1948       if (java::GeckoAppShell::UnlockProfile()) {
1949         return NS_LockProfilePath(aProfileDir, aProfileLocalDir,
1950                                   nullptr, aResult);
1951       }
1952 #else
1953       rv = ps->Alert(nullptr, killTitle, killMessage);
1954       NS_ENSURE_SUCCESS_LOG(rv, rv);
1955 #endif
1956     }
1957 
1958     return NS_ERROR_ABORT;
1959   }
1960 }
1961 
1962 static nsresult
ProfileMissingDialog(nsINativeAppSupport * aNative)1963 ProfileMissingDialog(nsINativeAppSupport* aNative)
1964 {
1965   nsresult rv;
1966 
1967   ScopedXPCOMStartup xpcom;
1968   rv = xpcom.Initialize();
1969   NS_ENSURE_SUCCESS(rv, rv);
1970 
1971   rv = xpcom.SetWindowCreator(aNative);
1972   NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
1973 
1974   { //extra scoping is needed so we release these components before xpcom shutdown
1975     nsCOMPtr<nsIStringBundleService> sbs =
1976       mozilla::services::GetStringBundleService();
1977     NS_ENSURE_TRUE(sbs, NS_ERROR_FAILURE);
1978 
1979     nsCOMPtr<nsIStringBundle> sb;
1980     sbs->CreateBundle(kProfileProperties, getter_AddRefs(sb));
1981     NS_ENSURE_TRUE_LOG(sbs, NS_ERROR_FAILURE);
1982 
1983     NS_ConvertUTF8toUTF16 appName(gAppData->name);
1984     const char16_t* params[] = {appName.get(), appName.get()};
1985 
1986     nsXPIDLString missingMessage;
1987 
1988     // profileMissing
1989     sb->FormatStringFromName(u"profileMissing", params, 2, getter_Copies(missingMessage));
1990 
1991     nsXPIDLString missingTitle;
1992     sb->FormatStringFromName(u"profileMissingTitle",
1993                              params, 1, getter_Copies(missingTitle));
1994 
1995     if (missingMessage && missingTitle) {
1996       nsCOMPtr<nsIPromptService> ps
1997         (do_GetService(NS_PROMPTSERVICE_CONTRACTID));
1998       NS_ENSURE_TRUE(ps, NS_ERROR_FAILURE);
1999 
2000       ps->Alert(nullptr, missingTitle, missingMessage);
2001     }
2002 
2003     return NS_ERROR_ABORT;
2004   }
2005 }
2006 
2007 static nsresult
ProfileLockedDialog(nsIToolkitProfile * aProfile,nsIProfileUnlocker * aUnlocker,nsINativeAppSupport * aNative,nsIProfileLock ** aResult)2008 ProfileLockedDialog(nsIToolkitProfile* aProfile, nsIProfileUnlocker* aUnlocker,
2009                     nsINativeAppSupport* aNative, nsIProfileLock* *aResult)
2010 {
2011   nsCOMPtr<nsIFile> profileDir;
2012   nsresult rv = aProfile->GetRootDir(getter_AddRefs(profileDir));
2013   if (NS_FAILED(rv)) return rv;
2014 
2015   bool exists;
2016   profileDir->Exists(&exists);
2017   if (!exists) {
2018     return ProfileMissingDialog(aNative);
2019   }
2020 
2021   nsCOMPtr<nsIFile> profileLocalDir;
2022   rv = aProfile->GetLocalDir(getter_AddRefs(profileLocalDir));
2023   if (NS_FAILED(rv)) return rv;
2024 
2025   return ProfileLockedDialog(profileDir, profileLocalDir, aUnlocker, aNative,
2026                              aResult);
2027 }
2028 
2029 static const char kProfileManagerURL[] =
2030   "chrome://mozapps/content/profile/profileSelection.xul";
2031 
2032 static ReturnAbortOnError
ShowProfileManager(nsIToolkitProfileService * aProfileSvc,nsINativeAppSupport * aNative)2033 ShowProfileManager(nsIToolkitProfileService* aProfileSvc,
2034                    nsINativeAppSupport* aNative)
2035 {
2036   if (!CanShowProfileManager()) {
2037     return NS_ERROR_NOT_IMPLEMENTED;
2038   }
2039 
2040   nsresult rv;
2041 
2042   nsCOMPtr<nsIFile> profD, profLD;
2043   char16_t* profileNamePtr;
2044   nsAutoCString profileName;
2045 
2046   {
2047     ScopedXPCOMStartup xpcom;
2048     rv = xpcom.Initialize();
2049     NS_ENSURE_SUCCESS(rv, rv);
2050 
2051     // Initialize the graphics prefs, some of the paths need them before
2052     // any other graphics is initialized (e.g., showing the profile chooser.)
2053     gfxPrefs::GetSingleton();
2054 
2055     rv = xpcom.SetWindowCreator(aNative);
2056     NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
2057 
2058 #ifdef XP_MACOSX
2059     CommandLineServiceMac::SetupMacCommandLine(gRestartArgc, gRestartArgv, true);
2060 #endif
2061 
2062 #ifdef XP_WIN
2063     // we don't have to wait here because profile manager window will pump
2064     // and DDE message will be handled
2065     ProcessDDE(aNative, false);
2066 #endif
2067 
2068     { //extra scoping is needed so we release these components before xpcom shutdown
2069       nsCOMPtr<nsIWindowWatcher> windowWatcher
2070         (do_GetService(NS_WINDOWWATCHER_CONTRACTID));
2071       nsCOMPtr<nsIDialogParamBlock> ioParamBlock
2072         (do_CreateInstance(NS_DIALOGPARAMBLOCK_CONTRACTID));
2073       nsCOMPtr<nsIMutableArray> dlgArray (do_CreateInstance(NS_ARRAY_CONTRACTID));
2074       NS_ENSURE_TRUE(windowWatcher && ioParamBlock && dlgArray, NS_ERROR_FAILURE);
2075 
2076       ioParamBlock->SetObjects(dlgArray);
2077 
2078       nsCOMPtr<nsIAppStartup> appStartup
2079         (do_GetService(NS_APPSTARTUP_CONTRACTID));
2080       NS_ENSURE_TRUE(appStartup, NS_ERROR_FAILURE);
2081 
2082       nsCOMPtr<mozIDOMWindowProxy> newWindow;
2083       rv = windowWatcher->OpenWindow(nullptr,
2084                                      kProfileManagerURL,
2085                                      "_blank",
2086                                      "centerscreen,chrome,modal,titlebar",
2087                                      ioParamBlock,
2088                                      getter_AddRefs(newWindow));
2089 
2090       NS_ENSURE_SUCCESS_LOG(rv, rv);
2091 
2092       aProfileSvc->Flush();
2093 
2094       int32_t dialogConfirmed;
2095       rv = ioParamBlock->GetInt(0, &dialogConfirmed);
2096       if (NS_FAILED(rv) || dialogConfirmed == 0) return NS_ERROR_ABORT;
2097 
2098       nsCOMPtr<nsIProfileLock> lock;
2099       rv = dlgArray->QueryElementAt(0, NS_GET_IID(nsIProfileLock),
2100                                     getter_AddRefs(lock));
2101       NS_ENSURE_SUCCESS_LOG(rv, rv);
2102 
2103       rv = lock->GetDirectory(getter_AddRefs(profD));
2104       NS_ENSURE_SUCCESS(rv, rv);
2105 
2106       rv = lock->GetLocalDirectory(getter_AddRefs(profLD));
2107       NS_ENSURE_SUCCESS(rv, rv);
2108 
2109       rv = ioParamBlock->GetString(0, &profileNamePtr);
2110       NS_ENSURE_SUCCESS(rv, rv);
2111 
2112       CopyUTF16toUTF8(profileNamePtr, profileName);
2113       free(profileNamePtr);
2114 
2115       lock->Unlock();
2116     }
2117   }
2118 
2119   SaveFileToEnv("XRE_PROFILE_PATH", profD);
2120   SaveFileToEnv("XRE_PROFILE_LOCAL_PATH", profLD);
2121   SaveWordToEnv("XRE_PROFILE_NAME", profileName);
2122 
2123   bool offline = false;
2124   aProfileSvc->GetStartOffline(&offline);
2125   if (offline) {
2126     SaveToEnv("XRE_START_OFFLINE=1");
2127   }
2128 
2129   return LaunchChild(aNative);
2130 }
2131 
2132 /**
2133  * Set the currently running profile as the default/selected one.
2134  *
2135  * @param aCurrentProfileRoot The root directory of the current profile.
2136  * @return an error if aCurrentProfileRoot is not found or the profile could not
2137  * be set as the default.
2138  */
2139 static nsresult
SetCurrentProfileAsDefault(nsIToolkitProfileService * aProfileSvc,nsIFile * aCurrentProfileRoot)2140 SetCurrentProfileAsDefault(nsIToolkitProfileService* aProfileSvc,
2141                            nsIFile* aCurrentProfileRoot)
2142 {
2143   NS_ENSURE_ARG_POINTER(aProfileSvc);
2144 
2145   nsCOMPtr<nsISimpleEnumerator> profiles;
2146   nsresult rv = aProfileSvc->GetProfiles(getter_AddRefs(profiles));
2147   if (NS_FAILED(rv))
2148     return rv;
2149 
2150   bool foundMatchingProfile = false;
2151   nsCOMPtr<nsISupports> supports;
2152   rv = profiles->GetNext(getter_AddRefs(supports));
2153   while (NS_SUCCEEDED(rv)) {
2154     nsCOMPtr<nsIToolkitProfile> profile = do_QueryInterface(supports);
2155     nsCOMPtr<nsIFile> profileRoot;
2156     profile->GetRootDir(getter_AddRefs(profileRoot));
2157     profileRoot->Equals(aCurrentProfileRoot, &foundMatchingProfile);
2158     if (foundMatchingProfile) {
2159       return aProfileSvc->SetSelectedProfile(profile);
2160     }
2161     rv = profiles->GetNext(getter_AddRefs(supports));
2162   }
2163   return rv;
2164 }
2165 
2166 static bool gDoMigration = false;
2167 static bool gDoProfileReset = false;
2168 static nsAutoCString gResetOldProfileName;
2169 
2170 // Pick a profile. We need to end up with a profile lock.
2171 //
2172 // 1) check for --profile <path>
2173 // 2) check for -P <name>
2174 // 3) check for --ProfileManager
2175 // 4) use the default profile, if there is one
2176 // 5) if there are *no* profiles, set up profile-migration
2177 // 6) display the profile-manager UI
2178 static nsresult
SelectProfile(nsIProfileLock ** aResult,nsIToolkitProfileService * aProfileSvc,nsINativeAppSupport * aNative,bool * aStartOffline,nsACString * aProfileName)2179 SelectProfile(nsIProfileLock* *aResult, nsIToolkitProfileService* aProfileSvc, nsINativeAppSupport* aNative,
2180               bool* aStartOffline, nsACString* aProfileName)
2181 {
2182   StartupTimeline::Record(StartupTimeline::SELECT_PROFILE);
2183 
2184   nsresult rv;
2185   ArgResult ar;
2186   const char* arg;
2187   *aResult = nullptr;
2188   *aStartOffline = false;
2189 
2190   ar = CheckArg("offline", true);
2191   if (ar == ARG_BAD) {
2192     PR_fprintf(PR_STDERR, "Error: argument --offline is invalid when argument --osint is specified\n");
2193     return NS_ERROR_FAILURE;
2194   }
2195 
2196   if (ar || EnvHasValue("XRE_START_OFFLINE"))
2197     *aStartOffline = true;
2198 
2199   if (EnvHasValue("MOZ_RESET_PROFILE_RESTART")) {
2200     gDoProfileReset = true;
2201     gDoMigration = true;
2202     SaveToEnv("MOZ_RESET_PROFILE_RESTART=");
2203   }
2204 
2205   // reset-profile and migration args need to be checked before any profiles are chosen below.
2206   ar = CheckArg("reset-profile", true);
2207   if (ar == ARG_BAD) {
2208     PR_fprintf(PR_STDERR, "Error: argument --reset-profile is invalid when argument --osint is specified\n");
2209     return NS_ERROR_FAILURE;
2210   } else if (ar == ARG_FOUND) {
2211     gDoProfileReset = true;
2212   }
2213 
2214   ar = CheckArg("migration", true);
2215   if (ar == ARG_BAD) {
2216     PR_fprintf(PR_STDERR, "Error: argument --migration is invalid when argument --osint is specified\n");
2217     return NS_ERROR_FAILURE;
2218   } else if (ar == ARG_FOUND) {
2219     gDoMigration = true;
2220   }
2221 
2222   nsCOMPtr<nsIFile> lf = GetFileFromEnv("XRE_PROFILE_PATH");
2223   if (lf) {
2224     nsCOMPtr<nsIFile> localDir =
2225       GetFileFromEnv("XRE_PROFILE_LOCAL_PATH");
2226     if (!localDir) {
2227       localDir = lf;
2228     }
2229 
2230     arg = PR_GetEnv("XRE_PROFILE_NAME");
2231     if (arg && *arg && aProfileName) {
2232       aProfileName->Assign(nsDependentCString(arg));
2233       if (gDoProfileReset) {
2234         gResetOldProfileName.Assign(*aProfileName);
2235       }
2236     }
2237 
2238     // Clear out flags that we handled (or should have handled!) last startup.
2239     const char *dummy;
2240     CheckArg("p", false, &dummy);
2241     CheckArg("profile", false, &dummy);
2242     CheckArg("profilemanager");
2243 
2244     if (gDoProfileReset) {
2245       // If we're resetting a profile, create a new one and use it to startup.
2246       nsCOMPtr<nsIToolkitProfile> newProfile;
2247       rv = CreateResetProfile(aProfileSvc, getter_AddRefs(newProfile));
2248       if (NS_SUCCEEDED(rv)) {
2249         rv = newProfile->GetRootDir(getter_AddRefs(lf));
2250         NS_ENSURE_SUCCESS(rv, rv);
2251         SaveFileToEnv("XRE_PROFILE_PATH", lf);
2252 
2253         rv = newProfile->GetLocalDir(getter_AddRefs(localDir));
2254         NS_ENSURE_SUCCESS(rv, rv);
2255         SaveFileToEnv("XRE_PROFILE_LOCAL_PATH", localDir);
2256 
2257         rv = newProfile->GetName(*aProfileName);
2258         if (NS_FAILED(rv))
2259           aProfileName->Truncate(0);
2260         SaveWordToEnv("XRE_PROFILE_NAME", *aProfileName);
2261       } else {
2262         NS_WARNING("Profile reset failed.");
2263         gDoProfileReset = false;
2264       }
2265     }
2266 
2267     return NS_LockProfilePath(lf, localDir, nullptr, aResult);
2268   }
2269 
2270   ar = CheckArg("profile", true, &arg);
2271   if (ar == ARG_BAD) {
2272     PR_fprintf(PR_STDERR, "Error: argument --profile requires a path\n");
2273     return NS_ERROR_FAILURE;
2274   }
2275   if (ar) {
2276     if (gDoProfileReset) {
2277       NS_WARNING("Profile reset is not supported in conjunction with --profile.");
2278       gDoProfileReset = false;
2279     }
2280 
2281     nsCOMPtr<nsIFile> lf;
2282     rv = XRE_GetFileFromPath(arg, getter_AddRefs(lf));
2283     NS_ENSURE_SUCCESS(rv, rv);
2284 
2285     nsCOMPtr<nsIProfileUnlocker> unlocker;
2286 
2287     // Check if the profile path exists and it's a directory.
2288     bool exists;
2289     lf->Exists(&exists);
2290     if (!exists) {
2291         rv = lf->Create(nsIFile::DIRECTORY_TYPE, 0700);
2292         NS_ENSURE_SUCCESS(rv, rv);
2293     }
2294 
2295     // If a profile path is specified directory on the command line, then
2296     // assume that the temp directory is the same as the given directory.
2297     rv = NS_LockProfilePath(lf, lf, getter_AddRefs(unlocker), aResult);
2298     if (NS_SUCCEEDED(rv))
2299       return rv;
2300 
2301     return ProfileLockedDialog(lf, lf, unlocker, aNative, aResult);
2302   }
2303 
2304   ar = CheckArg("createprofile", true, &arg);
2305   if (ar == ARG_BAD) {
2306     PR_fprintf(PR_STDERR, "Error: argument --createprofile requires a profile name\n");
2307     return NS_ERROR_FAILURE;
2308   }
2309   if (ar) {
2310     nsCOMPtr<nsIToolkitProfile> profile;
2311 
2312     const char* delim = strchr(arg, ' ');
2313     if (delim) {
2314       nsCOMPtr<nsIFile> lf;
2315       rv = NS_NewNativeLocalFile(nsDependentCString(delim + 1),
2316                                    true, getter_AddRefs(lf));
2317       if (NS_FAILED(rv)) {
2318         PR_fprintf(PR_STDERR, "Error: profile path not valid.\n");
2319         return rv;
2320       }
2321 
2322       // As with --profile, assume that the given path will be used for the
2323       // main profile directory.
2324       rv = aProfileSvc->CreateProfile(lf, nsDependentCSubstring(arg, delim),
2325                                      getter_AddRefs(profile));
2326     } else {
2327       rv = aProfileSvc->CreateProfile(nullptr, nsDependentCString(arg),
2328                                      getter_AddRefs(profile));
2329     }
2330     // Some pathological arguments can make it this far
2331     if (NS_FAILED(rv)) {
2332       PR_fprintf(PR_STDERR, "Error creating profile.\n");
2333       return rv;
2334     }
2335     rv = NS_ERROR_ABORT;
2336     aProfileSvc->Flush();
2337 
2338     // XXXben need to ensure prefs.js exists here so the tinderboxes will
2339     //        not go orange.
2340     nsCOMPtr<nsIFile> prefsJSFile;
2341     profile->GetRootDir(getter_AddRefs(prefsJSFile));
2342     prefsJSFile->AppendNative(NS_LITERAL_CSTRING("prefs.js"));
2343     nsAutoCString pathStr;
2344     prefsJSFile->GetNativePath(pathStr);
2345     PR_fprintf(PR_STDERR, "Success: created profile '%s' at '%s'\n", arg, pathStr.get());
2346     bool exists;
2347     prefsJSFile->Exists(&exists);
2348     if (!exists) {
2349       // Ignore any errors; we're about to return NS_ERROR_ABORT anyway.
2350       Unused << prefsJSFile->Create(nsIFile::NORMAL_FILE_TYPE, 0644);
2351     }
2352     // XXXdarin perhaps 0600 would be better?
2353 
2354     return rv;
2355   }
2356 
2357   uint32_t count;
2358   rv = aProfileSvc->GetProfileCount(&count);
2359   NS_ENSURE_SUCCESS(rv, rv);
2360 
2361   ar = CheckArg("p", false, &arg);
2362   if (ar == ARG_BAD) {
2363     ar = CheckArg("osint");
2364     if (ar == ARG_FOUND) {
2365       PR_fprintf(PR_STDERR, "Error: argument -p is invalid when argument --osint is specified\n");
2366       return NS_ERROR_FAILURE;
2367     }
2368 
2369     if (CanShowProfileManager()) {
2370       return ShowProfileManager(aProfileSvc, aNative);
2371     }
2372   }
2373   if (ar) {
2374     ar = CheckArg("osint");
2375     if (ar == ARG_FOUND) {
2376       PR_fprintf(PR_STDERR, "Error: argument -p is invalid when argument --osint is specified\n");
2377       return NS_ERROR_FAILURE;
2378     }
2379     nsCOMPtr<nsIToolkitProfile> profile;
2380     rv = aProfileSvc->GetProfileByName(nsDependentCString(arg),
2381                                       getter_AddRefs(profile));
2382     if (NS_SUCCEEDED(rv)) {
2383       if (gDoProfileReset) {
2384         {
2385           // Check that the source profile is not in use by temporarily acquiring its lock.
2386           nsIProfileLock* tempProfileLock;
2387           nsCOMPtr<nsIProfileUnlocker> unlocker;
2388           rv = profile->Lock(getter_AddRefs(unlocker), &tempProfileLock);
2389           if (NS_FAILED(rv))
2390             return ProfileLockedDialog(profile, unlocker, aNative, &tempProfileLock);
2391         }
2392 
2393         nsCOMPtr<nsIToolkitProfile> newProfile;
2394         rv = CreateResetProfile(aProfileSvc, getter_AddRefs(newProfile));
2395         if (NS_FAILED(rv)) {
2396           NS_WARNING("Failed to create a profile to reset to.");
2397           gDoProfileReset = false;
2398         } else {
2399           nsresult gotName = profile->GetName(gResetOldProfileName);
2400           if (NS_SUCCEEDED(gotName)) {
2401             profile = newProfile;
2402           } else {
2403             NS_WARNING("Failed to get the name of the profile we're resetting, so aborting reset.");
2404             gResetOldProfileName.Truncate(0);
2405             gDoProfileReset = false;
2406           }
2407         }
2408       }
2409 
2410       nsCOMPtr<nsIProfileUnlocker> unlocker;
2411       rv = profile->Lock(getter_AddRefs(unlocker), aResult);
2412       if (NS_SUCCEEDED(rv)) {
2413         if (aProfileName)
2414           aProfileName->Assign(nsDependentCString(arg));
2415         return NS_OK;
2416       }
2417 
2418       return ProfileLockedDialog(profile, unlocker, aNative, aResult);
2419     }
2420 
2421     if (CanShowProfileManager()) {
2422       return ShowProfileManager(aProfileSvc, aNative);
2423     }
2424   }
2425 
2426   ar = CheckArg("profilemanager", true);
2427   if (ar == ARG_BAD) {
2428     PR_fprintf(PR_STDERR, "Error: argument --profilemanager is invalid when argument --osint is specified\n");
2429     return NS_ERROR_FAILURE;
2430   } else if (ar == ARG_FOUND && CanShowProfileManager()) {
2431     return ShowProfileManager(aProfileSvc, aNative);
2432   }
2433 
2434 #ifndef MOZ_DEV_EDITION
2435   // If the only existing profile is the dev-edition-profile and this is not
2436   // Developer Edition, then no valid profiles were found.
2437   if (count == 1) {
2438     nsCOMPtr<nsIToolkitProfile> deProfile;
2439     // GetSelectedProfile will auto-select the only profile if there's just one
2440     aProfileSvc->GetSelectedProfile(getter_AddRefs(deProfile));
2441     nsAutoCString profileName;
2442     deProfile->GetName(profileName);
2443     if (profileName.EqualsLiteral("dev-edition-default")) {
2444       count = 0;
2445     }
2446   }
2447 #endif
2448 
2449   if (!count) {
2450     gDoMigration = true;
2451     gDoProfileReset = false;
2452 
2453     // create a default profile
2454     nsCOMPtr<nsIToolkitProfile> profile;
2455     nsresult rv = aProfileSvc->CreateProfile(nullptr, // choose a default dir for us
2456 #ifdef MOZ_DEV_EDITION
2457                                              NS_LITERAL_CSTRING("dev-edition-default"),
2458 #else
2459                                              NS_LITERAL_CSTRING("default"),
2460 #endif
2461                                              getter_AddRefs(profile));
2462     if (NS_SUCCEEDED(rv)) {
2463 #ifndef MOZ_DEV_EDITION
2464       aProfileSvc->SetDefaultProfile(profile);
2465 #endif
2466       aProfileSvc->Flush();
2467       rv = profile->Lock(nullptr, aResult);
2468       if (NS_SUCCEEDED(rv)) {
2469         if (aProfileName)
2470 #ifdef MOZ_DEV_EDITION
2471           aProfileName->AssignLiteral("dev-edition-default");
2472 #else
2473           aProfileName->AssignLiteral("default");
2474 #endif
2475         return NS_OK;
2476       }
2477     }
2478   }
2479 
2480   bool useDefault = true;
2481   if (count > 1 && CanShowProfileManager()) {
2482     aProfileSvc->GetStartWithLastProfile(&useDefault);
2483   }
2484 
2485   if (useDefault) {
2486     nsCOMPtr<nsIToolkitProfile> profile;
2487     // GetSelectedProfile will auto-select the only profile if there's just one
2488     aProfileSvc->GetSelectedProfile(getter_AddRefs(profile));
2489     if (profile) {
2490       // If we're resetting a profile, create a new one and use it to startup.
2491       if (gDoProfileReset) {
2492         {
2493           // Check that the source profile is not in use by temporarily acquiring its lock.
2494           nsIProfileLock* tempProfileLock;
2495           nsCOMPtr<nsIProfileUnlocker> unlocker;
2496           rv = profile->Lock(getter_AddRefs(unlocker), &tempProfileLock);
2497           if (NS_FAILED(rv))
2498             return ProfileLockedDialog(profile, unlocker, aNative, &tempProfileLock);
2499         }
2500 
2501         nsCOMPtr<nsIToolkitProfile> newProfile;
2502         rv = CreateResetProfile(aProfileSvc, getter_AddRefs(newProfile));
2503         if (NS_FAILED(rv)) {
2504           NS_WARNING("Failed to create a profile to reset to.");
2505           gDoProfileReset = false;
2506         } else {
2507           nsresult gotName = profile->GetName(gResetOldProfileName);
2508           if (NS_SUCCEEDED(gotName)) {
2509             profile = newProfile;
2510           } else {
2511             NS_WARNING("Failed to get the name of the profile we're resetting, so aborting reset.");
2512             gResetOldProfileName.Truncate(0);
2513             gDoProfileReset = false;
2514           }
2515         }
2516       }
2517 
2518       // If you close Firefox and very quickly reopen it, the old Firefox may
2519       // still be closing down. Rather than immediately showing the
2520       // "Firefox is running but is not responding" message, we spend a few
2521       // seconds retrying first.
2522 
2523       static const int kLockRetrySeconds = 5;
2524       static const int kLockRetrySleepMS = 100;
2525 
2526       nsCOMPtr<nsIProfileUnlocker> unlocker;
2527       const TimeStamp start = TimeStamp::Now();
2528       do {
2529         rv = profile->Lock(getter_AddRefs(unlocker), aResult);
2530         if (NS_SUCCEEDED(rv)) {
2531           StartupTimeline::Record(StartupTimeline::AFTER_PROFILE_LOCKED);
2532           // Try to grab the profile name.
2533           if (aProfileName) {
2534             rv = profile->GetName(*aProfileName);
2535             if (NS_FAILED(rv))
2536               aProfileName->Truncate(0);
2537           }
2538           return NS_OK;
2539         }
2540         PR_Sleep(kLockRetrySleepMS);
2541       } while (TimeStamp::Now() - start < TimeDuration::FromSeconds(kLockRetrySeconds));
2542 
2543       return ProfileLockedDialog(profile, unlocker, aNative, aResult);
2544     }
2545   }
2546 
2547   if (!CanShowProfileManager()) {
2548     return NS_ERROR_FAILURE;
2549   }
2550 
2551   return ShowProfileManager(aProfileSvc, aNative);
2552 }
2553 
2554 /**
2555  * Checks the compatibility.ini file to see if we have updated our application
2556  * or otherwise invalidated our caches. If the application has been updated,
2557  * we return false; otherwise, we return true. We also write the status
2558  * of the caches (valid/invalid) into the return param aCachesOK. The aCachesOK
2559  * is always invalid if the application has been updated.
2560  */
2561 static bool
CheckCompatibility(nsIFile * aProfileDir,const nsCString & aVersion,const nsCString & aOSABI,nsIFile * aXULRunnerDir,nsIFile * aAppDir,nsIFile * aFlagFile,bool * aCachesOK)2562 CheckCompatibility(nsIFile* aProfileDir, const nsCString& aVersion,
2563                    const nsCString& aOSABI, nsIFile* aXULRunnerDir,
2564                    nsIFile* aAppDir, nsIFile* aFlagFile,
2565                    bool* aCachesOK)
2566 {
2567   *aCachesOK = false;
2568   nsCOMPtr<nsIFile> file;
2569   aProfileDir->Clone(getter_AddRefs(file));
2570   if (!file)
2571     return false;
2572   file->AppendNative(FILE_COMPATIBILITY_INFO);
2573 
2574   nsINIParser parser;
2575   nsresult rv = parser.Init(file);
2576   if (NS_FAILED(rv))
2577     return false;
2578 
2579   nsAutoCString buf;
2580   rv = parser.GetString("Compatibility", "LastVersion", buf);
2581   if (NS_FAILED(rv) || !aVersion.Equals(buf))
2582     return false;
2583 
2584   rv = parser.GetString("Compatibility", "LastOSABI", buf);
2585   if (NS_FAILED(rv) || !aOSABI.Equals(buf))
2586     return false;
2587 
2588   rv = parser.GetString("Compatibility", "LastPlatformDir", buf);
2589   if (NS_FAILED(rv))
2590     return false;
2591 
2592   nsCOMPtr<nsIFile> lf;
2593   rv = NS_NewNativeLocalFile(buf, false,
2594                              getter_AddRefs(lf));
2595   if (NS_FAILED(rv))
2596     return false;
2597 
2598   bool eq;
2599   rv = lf->Equals(aXULRunnerDir, &eq);
2600   if (NS_FAILED(rv) || !eq)
2601     return false;
2602 
2603   if (aAppDir) {
2604     rv = parser.GetString("Compatibility", "LastAppDir", buf);
2605     if (NS_FAILED(rv))
2606       return false;
2607 
2608     rv = NS_NewNativeLocalFile(buf, false,
2609                                getter_AddRefs(lf));
2610     if (NS_FAILED(rv))
2611       return false;
2612 
2613     rv = lf->Equals(aAppDir, &eq);
2614     if (NS_FAILED(rv) || !eq)
2615       return false;
2616   }
2617 
2618   // If we see this flag, caches are invalid.
2619   rv = parser.GetString("Compatibility", "InvalidateCaches", buf);
2620   *aCachesOK = (NS_FAILED(rv) || !buf.EqualsLiteral("1"));
2621 
2622   bool purgeCaches = false;
2623   if (aFlagFile) {
2624     aFlagFile->Exists(&purgeCaches);
2625   }
2626 
2627   *aCachesOK = !purgeCaches && *aCachesOK;
2628   return true;
2629 }
2630 
BuildVersion(nsCString & aBuf)2631 static void BuildVersion(nsCString &aBuf)
2632 {
2633   aBuf.Assign(gAppData->version);
2634   aBuf.Append('_');
2635   aBuf.Append(gAppData->buildID);
2636   aBuf.Append('/');
2637   aBuf.Append(gToolkitBuildID);
2638 }
2639 
2640 static void
WriteVersion(nsIFile * aProfileDir,const nsCString & aVersion,const nsCString & aOSABI,nsIFile * aXULRunnerDir,nsIFile * aAppDir,bool invalidateCache)2641 WriteVersion(nsIFile* aProfileDir, const nsCString& aVersion,
2642              const nsCString& aOSABI, nsIFile* aXULRunnerDir,
2643              nsIFile* aAppDir, bool invalidateCache)
2644 {
2645   nsCOMPtr<nsIFile> file;
2646   aProfileDir->Clone(getter_AddRefs(file));
2647   if (!file)
2648     return;
2649   file->AppendNative(FILE_COMPATIBILITY_INFO);
2650 
2651   nsAutoCString platformDir;
2652   aXULRunnerDir->GetNativePath(platformDir);
2653 
2654   nsAutoCString appDir;
2655   if (aAppDir)
2656     aAppDir->GetNativePath(appDir);
2657 
2658   PRFileDesc *fd;
2659   nsresult rv =
2660     file->OpenNSPRFileDesc(PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, 0600, &fd);
2661   if (NS_FAILED(rv)) {
2662     NS_ERROR("could not create output stream");
2663     return;
2664   }
2665 
2666   static const char kHeader[] = "[Compatibility]" NS_LINEBREAK
2667                                 "LastVersion=";
2668 
2669   PR_Write(fd, kHeader, sizeof(kHeader) - 1);
2670   PR_Write(fd, aVersion.get(), aVersion.Length());
2671 
2672   static const char kOSABIHeader[] = NS_LINEBREAK "LastOSABI=";
2673   PR_Write(fd, kOSABIHeader, sizeof(kOSABIHeader) - 1);
2674   PR_Write(fd, aOSABI.get(), aOSABI.Length());
2675 
2676   static const char kPlatformDirHeader[] = NS_LINEBREAK "LastPlatformDir=";
2677 
2678   PR_Write(fd, kPlatformDirHeader, sizeof(kPlatformDirHeader) - 1);
2679   PR_Write(fd, platformDir.get(), platformDir.Length());
2680 
2681   static const char kAppDirHeader[] = NS_LINEBREAK "LastAppDir=";
2682   if (aAppDir) {
2683     PR_Write(fd, kAppDirHeader, sizeof(kAppDirHeader) - 1);
2684     PR_Write(fd, appDir.get(), appDir.Length());
2685   }
2686 
2687   static const char kInvalidationHeader[] = NS_LINEBREAK "InvalidateCaches=1";
2688   if (invalidateCache)
2689     PR_Write(fd, kInvalidationHeader, sizeof(kInvalidationHeader) - 1);
2690 
2691   static const char kNL[] = NS_LINEBREAK;
2692   PR_Write(fd, kNL, sizeof(kNL) - 1);
2693 
2694   PR_Close(fd);
2695 }
2696 
2697 /**
2698  * Returns true if the startup cache file was successfully removed.
2699  * Returns false if file->Clone fails at any point (OOM) or if unable
2700  * to remove the startup cache file. Note in particular the return value
2701  * is unaffected by a failure to remove extensions.ini
2702  */
2703 static bool
RemoveComponentRegistries(nsIFile * aProfileDir,nsIFile * aLocalProfileDir,bool aRemoveEMFiles)2704 RemoveComponentRegistries(nsIFile* aProfileDir, nsIFile* aLocalProfileDir,
2705                                       bool aRemoveEMFiles)
2706 {
2707   nsCOMPtr<nsIFile> file;
2708   aProfileDir->Clone(getter_AddRefs(file));
2709   if (!file)
2710     return false;
2711 
2712   if (aRemoveEMFiles) {
2713     file->SetNativeLeafName(NS_LITERAL_CSTRING("extensions.ini"));
2714     file->Remove(false);
2715   }
2716 
2717   aLocalProfileDir->Clone(getter_AddRefs(file));
2718   if (!file)
2719     return false;
2720 
2721 #if defined(XP_UNIX) || defined(XP_BEOS)
2722 #define PLATFORM_FASL_SUFFIX ".mfasl"
2723 #elif defined(XP_WIN)
2724 #define PLATFORM_FASL_SUFFIX ".mfl"
2725 #endif
2726 
2727   file->AppendNative(NS_LITERAL_CSTRING("XUL" PLATFORM_FASL_SUFFIX));
2728   file->Remove(false);
2729 
2730   file->SetNativeLeafName(NS_LITERAL_CSTRING("XPC" PLATFORM_FASL_SUFFIX));
2731   file->Remove(false);
2732 
2733   file->SetNativeLeafName(NS_LITERAL_CSTRING("startupCache"));
2734   nsresult rv = file->Remove(true);
2735   return NS_SUCCEEDED(rv) || rv == NS_ERROR_FILE_TARGET_DOES_NOT_EXIST;
2736 }
2737 
2738 // To support application initiated restart via nsIAppStartup.quit, we
2739 // need to save various environment variables, and then restore them
2740 // before re-launching the application.
2741 
2742 static struct SavedVar {
2743   const char *name;
2744   char *value;
2745 } gSavedVars[] = {
2746   {"XUL_APP_FILE", nullptr}
2747 };
2748 
SaveStateForAppInitiatedRestart()2749 static void SaveStateForAppInitiatedRestart()
2750 {
2751   for (size_t i = 0; i < ArrayLength(gSavedVars); ++i) {
2752     const char *s = PR_GetEnv(gSavedVars[i].name);
2753     if (s)
2754       gSavedVars[i].value = PR_smprintf("%s=%s", gSavedVars[i].name, s);
2755   }
2756 }
2757 
RestoreStateForAppInitiatedRestart()2758 static void RestoreStateForAppInitiatedRestart()
2759 {
2760   for (size_t i = 0; i < ArrayLength(gSavedVars); ++i) {
2761     if (gSavedVars[i].value)
2762       PR_SetEnv(gSavedVars[i].value);
2763   }
2764 }
2765 
2766 #ifdef MOZ_CRASHREPORTER
2767 // When we first initialize the crash reporter we don't have a profile,
2768 // so we set the minidump path to $TEMP.  Once we have a profile,
2769 // we set it to $PROFILE/minidumps, creating the directory
2770 // if needed.
MakeOrSetMinidumpPath(nsIFile * profD)2771 static void MakeOrSetMinidumpPath(nsIFile* profD)
2772 {
2773   nsCOMPtr<nsIFile> dumpD;
2774   profD->Clone(getter_AddRefs(dumpD));
2775 
2776   if (dumpD) {
2777     bool fileExists;
2778     //XXX: do some more error checking here
2779     dumpD->Append(NS_LITERAL_STRING("minidumps"));
2780     dumpD->Exists(&fileExists);
2781     if (!fileExists) {
2782       nsresult rv = dumpD->Create(nsIFile::DIRECTORY_TYPE, 0700);
2783       NS_ENSURE_SUCCESS_VOID(rv);
2784     }
2785 
2786     nsAutoString pathStr;
2787     if (NS_SUCCEEDED(dumpD->GetPath(pathStr)))
2788       CrashReporter::SetMinidumpPath(pathStr);
2789   }
2790 }
2791 #endif
2792 
2793 const nsXREAppData* gAppData = nullptr;
2794 
2795 #ifdef MOZ_WIDGET_GTK
MOZ_gdk_display_close(GdkDisplay * display)2796 static void MOZ_gdk_display_close(GdkDisplay *display)
2797 {
2798 #if CLEANUP_MEMORY
2799   // XXX wallpaper for bug 417163: don't close the Display if we're using the
2800   // Qt theme because we crash (in Qt code) when using jemalloc.
2801   bool skip_display_close = false;
2802   GtkSettings* settings =
2803     gtk_settings_get_for_screen(gdk_display_get_default_screen(display));
2804   gchar *theme_name;
2805   g_object_get(settings, "gtk-theme-name", &theme_name, nullptr);
2806   if (theme_name) {
2807     skip_display_close = strcmp(theme_name, "Qt") == 0;
2808     if (skip_display_close)
2809       NS_WARNING("wallpaper bug 417163 for Qt theme");
2810     g_free(theme_name);
2811   }
2812 
2813 #if (MOZ_WIDGET_GTK == 3)
2814   // A workaround for https://bugzilla.gnome.org/show_bug.cgi?id=703257
2815   if (gtk_check_version(3,9,8) != NULL)
2816     skip_display_close = true;
2817 #endif
2818 
2819   // Get a (new) Pango context that holds a reference to the fontmap that
2820   // GTK has been using.  gdk_pango_context_get() must be called while GTK
2821   // has a default display.
2822   PangoContext *pangoContext = gdk_pango_context_get();
2823 
2824   bool buggyCairoShutdown = cairo_version() < CAIRO_VERSION_ENCODE(1, 4, 0);
2825 
2826   if (!buggyCairoShutdown) {
2827     // We should shut down GDK before we shut down libraries it depends on
2828     // like Pango and cairo. But if cairo shutdown is buggy, we should
2829     // shut down cairo first otherwise it may crash because of dangling
2830     // references to Display objects (see bug 469831).
2831     if (!skip_display_close)
2832       gdk_display_close(display);
2833   }
2834 
2835   // Clean up PangoCairo's default fontmap.
2836   // This pango_fc_font_map_shutdown call (and the associated code to
2837   // get the font map) really shouldn't be needed anymore, except that
2838   // it's needed to avoid having cairo_debug_reset_static_data fatally
2839   // assert if we've leaked other things that hold on to the fontmap,
2840   // which is something that currently happens in mochitest-plugins.
2841   // Even if it didn't happen in mochitest-plugins, we probably want to
2842   // avoid the crash-on-leak problem since it makes it harder to use
2843   // many of our leak tools to debug leaks.
2844 
2845   // This doesn't take a reference.
2846   PangoFontMap *fontmap = pango_context_get_font_map(pangoContext);
2847   // Do some shutdown of the fontmap, which releases the fonts, clearing a
2848   // bunch of circular references from the fontmap through the fonts back to
2849   // itself.  The shutdown that this does is much less than what's done by
2850   // the fontmap's finalize, though.
2851   if (PANGO_IS_FC_FONT_MAP(fontmap))
2852       pango_fc_font_map_shutdown(PANGO_FC_FONT_MAP(fontmap));
2853   g_object_unref(pangoContext);
2854 
2855   // Tell PangoCairo to release its default fontmap.
2856   pango_cairo_font_map_set_default(nullptr);
2857 
2858   // cairo_debug_reset_static_data() is prototyped through cairo.h included
2859   // by gtk.h.
2860 #ifdef cairo_debug_reset_static_data
2861 #error "Looks like we're including Mozilla's cairo instead of system cairo"
2862 #endif
2863   cairo_debug_reset_static_data();
2864   // FIXME: Do we need to call this in non-GTK2 cases as well?
2865   FcFini();
2866 
2867   if (buggyCairoShutdown) {
2868     if (!skip_display_close)
2869       gdk_display_close(display);
2870   }
2871 #else // not CLEANUP_MEMORY
2872   // Don't do anything to avoid running into driver bugs under XCloseDisplay().
2873   // See bug 973192.
2874   (void) display;
2875 #endif
2876 }
2877 
detectDisplay(void)2878 static const char* detectDisplay(void)
2879 {
2880   bool tryX11 = false;
2881   bool tryWayland = false;
2882   bool tryBroadway = false;
2883 
2884   // Honor user backend selection
2885   const char *backend = PR_GetEnv("GDK_BACKEND");
2886   if (!backend || strstr(backend, "*")) {
2887     // Try all backends
2888     tryX11 = true;
2889     tryWayland = true;
2890     tryBroadway = true;
2891   } else if (backend) {
2892     if (strstr(backend, "x11"))
2893       tryX11 = true;
2894     if (strstr(backend, "wayland"))
2895       tryWayland = true;
2896     if (strstr(backend, "broadway"))
2897       tryBroadway = true;
2898   }
2899 
2900   const char *display_name;
2901   if (tryX11 && (display_name = PR_GetEnv("DISPLAY"))) {
2902     return display_name;
2903   } else if (tryWayland && (display_name = PR_GetEnv("WAYLAND_DISPLAY"))) {
2904     return display_name;
2905   } else if (tryBroadway && (display_name = PR_GetEnv("BROADWAY_DISPLAY"))) {
2906     return display_name;
2907   }
2908 
2909   PR_fprintf(PR_STDERR, "Error: GDK_BACKEND does not match available displays\n");
2910   return nullptr;
2911 }
2912 #endif // MOZ_WIDGET_GTK
2913 
2914 /**
2915  * NSPR will search for the "nspr_use_zone_allocator" symbol throughout
2916  * the process and use it to determine whether the application defines its own
2917  * memory allocator or not.
2918  *
2919  * Since most applications (e.g. Firefox and Thunderbird) don't use any special
2920  * allocators and therefore don't define this symbol, NSPR must search the
2921  * entire process, which reduces startup performance.
2922  *
2923  * By defining the symbol here, we can avoid the wasted lookup and hopefully
2924  * improve startup performance.
2925  */
2926 NS_VISIBILITY_DEFAULT PRBool nspr_use_zone_allocator = PR_FALSE;
2927 
2928 #ifdef CAIRO_HAS_DWRITE_FONT
2929 
2930 #include <dwrite.h>
2931 
2932 #ifdef DEBUG_DWRITE_STARTUP
2933 
2934 #define LOGREGISTRY(msg) LogRegistryEvent(msg)
2935 
2936 // for use when monitoring process
LogRegistryEvent(const wchar_t * msg)2937 static void LogRegistryEvent(const wchar_t *msg)
2938 {
2939   HKEY dummyKey;
2940   HRESULT hr;
2941   wchar_t buf[512];
2942 
2943   wsprintf(buf, L" log %s", msg);
2944   hr = RegOpenKeyEx(HKEY_LOCAL_MACHINE, buf, 0, KEY_READ, &dummyKey);
2945   if (SUCCEEDED(hr)) {
2946     RegCloseKey(dummyKey);
2947   }
2948 }
2949 #else
2950 
2951 #define LOGREGISTRY(msg)
2952 
2953 #endif
2954 
InitDwriteBG(LPVOID lpdwThreadParam)2955 static DWORD WINAPI InitDwriteBG(LPVOID lpdwThreadParam)
2956 {
2957   SetThreadPriority(GetCurrentThread(), THREAD_MODE_BACKGROUND_BEGIN);
2958   LOGREGISTRY(L"loading dwrite.dll");
2959   HMODULE dwdll = LoadLibraryW(L"dwrite.dll");
2960   if (dwdll) {
2961     decltype(DWriteCreateFactory)* createDWriteFactory = (decltype(DWriteCreateFactory)*)
2962       GetProcAddress(dwdll, "DWriteCreateFactory");
2963     if (createDWriteFactory) {
2964       LOGREGISTRY(L"creating dwrite factory");
2965       IDWriteFactory *factory;
2966       HRESULT hr = createDWriteFactory(
2967         DWRITE_FACTORY_TYPE_SHARED,
2968         __uuidof(IDWriteFactory),
2969         reinterpret_cast<IUnknown**>(&factory));
2970       if (SUCCEEDED(hr)) {
2971         LOGREGISTRY(L"dwrite factory done");
2972         factory->Release();
2973         LOGREGISTRY(L"freed factory");
2974       } else {
2975         LOGREGISTRY(L"failed to create factory");
2976       }
2977     }
2978   }
2979   SetThreadPriority(GetCurrentThread(), THREAD_MODE_BACKGROUND_END);
2980   return 0;
2981 }
2982 #endif
2983 
2984 #ifdef USE_GLX_TEST
2985 bool fire_glxtest_process();
2986 #endif
2987 
2988 #include "GeckoProfiler.h"
2989 
2990 // Encapsulates startup and shutdown state for XRE_main
2991 class XREMain
2992 {
2993 public:
XREMain()2994   XREMain() :
2995     mStartOffline(false)
2996     , mShuttingDown(false)
2997 #ifdef MOZ_ENABLE_XREMOTE
2998     , mDisableRemote(false)
2999 #endif
3000 #if defined(MOZ_WIDGET_GTK)
3001     , mGdkDisplay(nullptr)
3002 #endif
3003   {};
3004 
~XREMain()3005   ~XREMain() {
3006     mScopedXPCOM = nullptr;
3007     mAppData = nullptr;
3008   }
3009 
3010   int XRE_main(int argc, char* argv[], const nsXREAppData* aAppData);
3011   int XRE_mainInit(bool* aExitFlag);
3012   int XRE_mainStartup(bool* aExitFlag);
3013   nsresult XRE_mainRun();
3014 
3015   nsCOMPtr<nsINativeAppSupport> mNativeApp;
3016   nsCOMPtr<nsIToolkitProfileService> mProfileSvc;
3017   nsCOMPtr<nsIFile> mProfD;
3018   nsCOMPtr<nsIFile> mProfLD;
3019   nsCOMPtr<nsIProfileLock> mProfileLock;
3020 #ifdef MOZ_ENABLE_XREMOTE
3021   nsCOMPtr<nsIRemoteService> mRemoteService;
3022   nsProfileLock mRemoteLock;
3023   nsCOMPtr<nsIFile> mRemoteLockDir;
3024 #endif
3025 
3026   UniquePtr<ScopedXPCOMStartup> mScopedXPCOM;
3027   nsAutoPtr<mozilla::ScopedAppData> mAppData;
3028 
3029   nsXREDirProvider mDirProvider;
3030   nsAutoCString mProfileName;
3031   nsAutoCString mDesktopStartupID;
3032 
3033   bool mStartOffline;
3034   bool mShuttingDown;
3035 #ifdef MOZ_ENABLE_XREMOTE
3036   bool mDisableRemote;
3037 #endif
3038 
3039 #if defined(MOZ_WIDGET_GTK)
3040   GdkDisplay* mGdkDisplay;
3041 #endif
3042 };
3043 
3044 /*
3045  * XRE_mainInit - Initial setup and command line parameter processing.
3046  * Main() will exit early if either return value != 0 or if aExitFlag is
3047  * true.
3048  */
3049 int
XRE_mainInit(bool * aExitFlag)3050 XREMain::XRE_mainInit(bool* aExitFlag)
3051 {
3052   if (!aExitFlag)
3053     return 1;
3054   *aExitFlag = false;
3055 
3056   atexit(UnexpectedExit);
3057   auto expectedShutdown = mozilla::MakeScopeExit([&] {
3058     MozExpectedExit();
3059   });
3060 
3061   StartupTimeline::Record(StartupTimeline::MAIN);
3062 
3063   if (PR_GetEnv("MOZ_CHAOSMODE")) {
3064     ChaosFeature feature = ChaosFeature::Any;
3065     long featureInt = strtol(PR_GetEnv("MOZ_CHAOSMODE"), nullptr, 16);
3066     if (featureInt) {
3067       // NOTE: MOZ_CHAOSMODE=0 or a non-hex value maps to Any feature.
3068       feature = static_cast<ChaosFeature>(featureInt);
3069     }
3070     ChaosMode::SetChaosFeature(feature);
3071   }
3072 
3073   if (ChaosMode::isActive(ChaosFeature::Any)) {
3074     printf_stderr("*** You are running in chaos test mode. See ChaosMode.h. ***\n");
3075   }
3076 
3077   nsresult rv;
3078   ArgResult ar;
3079 
3080 #ifdef DEBUG
3081   if (PR_GetEnv("XRE_MAIN_BREAK"))
3082     NS_BREAK();
3083 #endif
3084 
3085 #ifdef USE_GLX_TEST
3086   // bug 639842 - it's very important to fire this process BEFORE we set up
3087   // error handling. indeed, this process is expected to be crashy, and we
3088   // don't want the user to see its crashes. That's the whole reason for
3089   // doing this in a separate process.
3090   //
3091   // This call will cause a fork and the fork will terminate itself separately
3092   // from the usual shutdown sequence
3093   fire_glxtest_process();
3094 #endif
3095 
3096   SetupErrorHandling(gArgv[0]);
3097 
3098 #ifdef CAIRO_HAS_DWRITE_FONT
3099   {
3100     // Bug 602792 - when DWriteCreateFactory is called the dwrite client dll
3101     // starts the FntCache service if it isn't already running (it's set
3102     // to manual startup by default in Windows 7 RTM).  Subsequent DirectWrite
3103     // calls cause the IDWriteFactory object to communicate with the FntCache
3104     // service with a timeout; if there's no response after the timeout, the
3105     // DirectWrite client library will assume the service isn't around and do
3106     // manual font file I/O on _all_ system fonts.  To avoid this, load the
3107     // dwrite library and create a factory as early as possible so that the
3108     // FntCache service is ready by the time it's needed.
3109 
3110     if (IsVistaOrLater()) {
3111       CreateThread(nullptr, 0, &InitDwriteBG, nullptr, 0, nullptr);
3112     }
3113   }
3114 #endif
3115 
3116 #ifdef XP_UNIX
3117   const char *home = PR_GetEnv("HOME");
3118   if (!home || !*home) {
3119     struct passwd *pw = getpwuid(geteuid());
3120     if (!pw || !pw->pw_dir) {
3121       Output(true, "Could not determine HOME directory");
3122       return 1;
3123     }
3124     SaveWordToEnv("HOME", nsDependentCString(pw->pw_dir));
3125   }
3126 #endif
3127 
3128 #ifdef MOZ_ACCESSIBILITY_ATK
3129   // Suppress atk-bridge init at startup, until mozilla accessibility is
3130   // initialized.  This works after gnome 2.24.2.
3131   SaveToEnv("NO_AT_BRIDGE=1");
3132 #endif
3133 
3134   // Check for application.ini overrides
3135   const char* override = nullptr;
3136   ar = CheckArg("override", true, &override);
3137   if (ar == ARG_BAD) {
3138     Output(true, "Incorrect number of arguments passed to --override");
3139     return 1;
3140   }
3141   else if (ar == ARG_FOUND) {
3142     nsCOMPtr<nsIFile> overrideLF;
3143     rv = XRE_GetFileFromPath(override, getter_AddRefs(overrideLF));
3144     if (NS_FAILED(rv)) {
3145       Output(true, "Error: unrecognized override.ini path.\n");
3146       return 1;
3147     }
3148 
3149     rv = XRE_ParseAppData(overrideLF, mAppData.get());
3150     if (NS_FAILED(rv)) {
3151       Output(true, "Couldn't read override.ini");
3152       return 1;
3153     }
3154   }
3155 
3156   // Check sanity and correctness of app data.
3157 
3158   if (!mAppData->name) {
3159     Output(true, "Error: App:Name not specified in application.ini\n");
3160     return 1;
3161   }
3162   if (!mAppData->buildID) {
3163     Output(true, "Error: App:BuildID not specified in application.ini\n");
3164     return 1;
3165   }
3166 
3167   // XXX Originally ScopedLogging was here? Now it's in XRE_main above
3168   // XRE_mainInit.
3169 
3170   if (!mAppData->xreDirectory) {
3171     nsCOMPtr<nsIFile> lf;
3172     rv = XRE_GetBinaryPath(gArgv[0], getter_AddRefs(lf));
3173     if (NS_FAILED(rv))
3174       return 2;
3175 
3176     nsCOMPtr<nsIFile> greDir;
3177     rv = lf->GetParent(getter_AddRefs(greDir));
3178     if (NS_FAILED(rv))
3179       return 2;
3180 
3181 #ifdef XP_MACOSX
3182     nsCOMPtr<nsIFile> parent;
3183     greDir->GetParent(getter_AddRefs(parent));
3184     greDir = parent.forget();
3185     greDir->AppendNative(NS_LITERAL_CSTRING("Resources"));
3186 #endif
3187 
3188     greDir.forget(&mAppData->xreDirectory);
3189   }
3190 
3191   if (!mAppData->directory) {
3192     NS_IF_ADDREF(mAppData->directory = mAppData->xreDirectory);
3193   }
3194 
3195   if (mAppData->size > offsetof(nsXREAppData, minVersion)) {
3196     if (!mAppData->minVersion) {
3197       Output(true, "Error: Gecko:MinVersion not specified in application.ini\n");
3198       return 1;
3199     }
3200 
3201     if (!mAppData->maxVersion) {
3202       // If no maxVersion is specified, we assume the app is only compatible
3203       // with the initial preview release. Do not increment this number ever!
3204       SetAllocatedString(mAppData->maxVersion, "1.*");
3205     }
3206 
3207     if (mozilla::Version(mAppData->minVersion) > gToolkitVersion ||
3208         mozilla::Version(mAppData->maxVersion) < gToolkitVersion) {
3209       Output(true, "Error: Platform version '%s' is not compatible with\n"
3210              "minVersion >= %s\nmaxVersion <= %s\n",
3211              gToolkitVersion,
3212              mAppData->minVersion, mAppData->maxVersion);
3213       return 1;
3214     }
3215   }
3216 
3217   rv = mDirProvider.Initialize(mAppData->directory, mAppData->xreDirectory);
3218   if (NS_FAILED(rv))
3219     return 1;
3220 
3221 #ifdef MOZ_CRASHREPORTER
3222   if (EnvHasValue("MOZ_CRASHREPORTER")) {
3223     mAppData->flags |= NS_XRE_ENABLE_CRASH_REPORTER;
3224   }
3225 
3226   nsCOMPtr<nsIFile> xreBinDirectory;
3227   xreBinDirectory = mDirProvider.GetGREBinDir();
3228 
3229   if ((mAppData->flags & NS_XRE_ENABLE_CRASH_REPORTER) &&
3230       NS_SUCCEEDED(
3231         CrashReporter::SetExceptionHandler(xreBinDirectory))) {
3232     nsCOMPtr<nsIFile> file;
3233     rv = mDirProvider.GetUserAppDataDirectory(getter_AddRefs(file));
3234     if (NS_SUCCEEDED(rv)) {
3235       CrashReporter::SetUserAppDataDirectory(file);
3236     }
3237     if (mAppData->crashReporterURL)
3238       CrashReporter::SetServerURL(nsDependentCString(mAppData->crashReporterURL));
3239 
3240     // We overwrite this once we finish starting up.
3241     CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("StartupCrash"),
3242                                        NS_LITERAL_CSTRING("1"));
3243 
3244     // pass some basic info from the app data
3245     if (mAppData->vendor)
3246       CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("Vendor"),
3247                                          nsDependentCString(mAppData->vendor));
3248     if (mAppData->name)
3249       CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("ProductName"),
3250                                          nsDependentCString(mAppData->name));
3251     if (mAppData->ID)
3252       CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("ProductID"),
3253                                          nsDependentCString(mAppData->ID));
3254     if (mAppData->version)
3255       CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("Version"),
3256                                          nsDependentCString(mAppData->version));
3257     if (mAppData->buildID)
3258       CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("BuildID"),
3259                                          nsDependentCString(mAppData->buildID));
3260 
3261     nsDependentCString releaseChannel(NS_STRINGIFY(MOZ_UPDATE_CHANNEL));
3262     CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("ReleaseChannel"),
3263                                        releaseChannel);
3264 #ifdef MOZ_LINKER
3265     CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("CrashAddressLikelyWrong"),
3266                                        IsSignalHandlingBroken() ? NS_LITERAL_CSTRING("1")
3267                                                                 : NS_LITERAL_CSTRING("0"));
3268 #endif
3269 
3270 #ifdef XP_WIN
3271     nsAutoString appInitDLLs;
3272     if (widget::WinUtils::GetAppInitDLLs(appInitDLLs)) {
3273       CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("AppInitDLLs"),
3274                                          NS_ConvertUTF16toUTF8(appInitDLLs));
3275     }
3276 #endif
3277 
3278     CrashReporter::SetRestartArgs(gArgc, gArgv);
3279 
3280     // annotate other data (user id etc)
3281     nsCOMPtr<nsIFile> userAppDataDir;
3282     if (NS_SUCCEEDED(mDirProvider.GetUserAppDataDirectory(
3283                                                          getter_AddRefs(userAppDataDir)))) {
3284       CrashReporter::SetupExtraData(userAppDataDir,
3285                                     nsDependentCString(mAppData->buildID));
3286 
3287       // see if we have a crashreporter-override.ini in the application directory
3288       nsCOMPtr<nsIFile> overrideini;
3289       bool exists;
3290       if (NS_SUCCEEDED(mDirProvider.GetAppDir()->Clone(getter_AddRefs(overrideini))) &&
3291           NS_SUCCEEDED(overrideini->AppendNative(NS_LITERAL_CSTRING("crashreporter-override.ini"))) &&
3292           NS_SUCCEEDED(overrideini->Exists(&exists)) &&
3293           exists) {
3294 #ifdef XP_WIN
3295         nsAutoString overridePathW;
3296         overrideini->GetPath(overridePathW);
3297         NS_ConvertUTF16toUTF8 overridePath(overridePathW);
3298 #else
3299         nsAutoCString overridePath;
3300         overrideini->GetNativePath(overridePath);
3301 #endif
3302 
3303         SaveWordToEnv("MOZ_CRASHREPORTER_STRINGS_OVERRIDE", overridePath);
3304       }
3305     }
3306   }
3307 #endif
3308 
3309 #if defined(MOZ_SANDBOX) && defined(XP_WIN)
3310   if (mAppData->sandboxBrokerServices) {
3311     SandboxBroker::Initialize(mAppData->sandboxBrokerServices);
3312     Telemetry::Accumulate(Telemetry::SANDBOX_BROKER_INITIALIZED, true);
3313   } else {
3314     Telemetry::Accumulate(Telemetry::SANDBOX_BROKER_INITIALIZED, false);
3315 #if defined(MOZ_CONTENT_SANDBOX)
3316     // If we're sandboxing content and we fail to initialize, then crashing here
3317     // seems like the sensible option.
3318     if (BrowserTabsRemoteAutostart()) {
3319       MOZ_CRASH("Failed to initialize broker services, can't continue.");
3320     }
3321 #endif
3322     // Otherwise just warn for the moment, as most things will work.
3323     NS_WARNING("Failed to initialize broker services, sandboxed processes will "
3324                "fail to start.");
3325   }
3326 #endif
3327 
3328 #ifdef XP_MACOSX
3329   // Set up ability to respond to system (Apple) events. This must occur before
3330   // ProcessUpdates to ensure that links clicked in external applications aren't
3331   // lost when updates are pending.
3332   SetupMacApplicationDelegate();
3333 
3334   if (EnvHasValue("MOZ_LAUNCHED_CHILD")) {
3335     // This is needed, on relaunch, to force the OS to use the "Cocoa Dock
3336     // API".  Otherwise the call to ReceiveNextEvent() below will make it
3337     // use the "Carbon Dock API".  For more info see bmo bug 377166.
3338     EnsureUseCocoaDockAPI();
3339 
3340     // When the app relaunches, the original process exits.  This causes
3341     // the dock tile to stop bouncing, lose the "running" triangle, and
3342     // if the tile does not permanently reside in the Dock, even disappear.
3343     // This can be confusing to the user, who is expecting the app to launch.
3344     // Calling ReceiveNextEvent without requesting any event is enough to
3345     // cause a dock tile for the child process to appear.
3346     const EventTypeSpec kFakeEventList[] = { { INT_MAX, INT_MAX } };
3347     EventRef event;
3348     ::ReceiveNextEvent(GetEventTypeCount(kFakeEventList), kFakeEventList,
3349                        kEventDurationNoWait, false, &event);
3350   }
3351 
3352   if (CheckArg("foreground")) {
3353     // The original process communicates that it was in the foreground by
3354     // adding this argument.  This new process, which is taking over for
3355     // the old one, should make itself the active application.
3356     ProcessSerialNumber psn;
3357     if (::GetCurrentProcess(&psn) == noErr)
3358       ::SetFrontProcess(&psn);
3359   }
3360 #endif
3361 
3362   SaveToEnv("MOZ_LAUNCHED_CHILD=");
3363 
3364   gRestartArgc = gArgc;
3365   gRestartArgv = (char**) malloc(sizeof(char*) * (gArgc + 1 + (override ? 2 : 0)));
3366   if (!gRestartArgv) {
3367     return 1;
3368   }
3369 
3370   int i;
3371   for (i = 0; i < gArgc; ++i) {
3372     gRestartArgv[i] = gArgv[i];
3373   }
3374 
3375   // Add the -override argument back (it is removed automatically be CheckArg) if there is one
3376   if (override) {
3377     gRestartArgv[gRestartArgc++] = const_cast<char*>("-override");
3378     gRestartArgv[gRestartArgc++] = const_cast<char*>(override);
3379   }
3380 
3381   gRestartArgv[gRestartArgc] = nullptr;
3382 
3383 
3384   if (EnvHasValue("MOZ_SAFE_MODE_RESTART")) {
3385     gSafeMode = true;
3386     // unset the env variable
3387     SaveToEnv("MOZ_SAFE_MODE_RESTART=");
3388   }
3389 
3390   ar = CheckArg("safe-mode", true);
3391   if (ar == ARG_BAD) {
3392     PR_fprintf(PR_STDERR, "Error: argument --safe-mode is invalid when argument --osint is specified\n");
3393     return 1;
3394   } else if (ar == ARG_FOUND) {
3395     gSafeMode = true;
3396   }
3397 
3398 #ifdef XP_WIN
3399   // If the shift key is pressed and the ctrl and / or alt keys are not pressed
3400   // during startup start in safe mode. GetKeyState returns a short and the high
3401   // order bit will be 1 if the key is pressed. By masking the returned short
3402   // with 0x8000 the result will be 0 if the key is not pressed and non-zero
3403   // otherwise.
3404   if ((GetKeyState(VK_SHIFT) & 0x8000) &&
3405       !(GetKeyState(VK_CONTROL) & 0x8000) &&
3406       !(GetKeyState(VK_MENU) & 0x8000) &&
3407       !EnvHasValue("MOZ_DISABLE_SAFE_MODE_KEY")) {
3408     gSafeMode = true;
3409   }
3410 #endif
3411 
3412 #ifdef XP_MACOSX
3413   if ((GetCurrentEventKeyModifiers() & optionKey) &&
3414       !EnvHasValue("MOZ_DISABLE_SAFE_MODE_KEY"))
3415     gSafeMode = true;
3416 #endif
3417 
3418 #ifdef XP_WIN
3419   {
3420     // Add CPU microcode version to the crash report as "CPUMicrocodeVersion".
3421     // It feels like this code may belong in nsSystemInfo instead.
3422     int cpuUpdateRevision = -1;
3423     HKEY key;
3424     static const WCHAR keyName[] =
3425       L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0";
3426 
3427     if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, keyName , 0, KEY_QUERY_VALUE, &key) == ERROR_SUCCESS) {
3428 
3429       DWORD updateRevision[2];
3430       DWORD len = sizeof(updateRevision);
3431       DWORD vtype;
3432 
3433       // Windows 7 uses "Update Signature", 8 uses "Update Revision".
3434       // For AMD CPUs, "CurrentPatchLevel" is sometimes used.
3435       // Take the first one we find.
3436       LPCWSTR choices[] = {L"Update Signature", L"Update Revision", L"CurrentPatchLevel"};
3437       for (size_t oneChoice=0; oneChoice<ArrayLength(choices); oneChoice++) {
3438         if (RegQueryValueExW(key, choices[oneChoice],
3439                              0, &vtype,
3440                              reinterpret_cast<LPBYTE>(updateRevision),
3441                              &len) == ERROR_SUCCESS) {
3442           if (vtype == REG_BINARY && len == sizeof(updateRevision)) {
3443             // The first word is unused
3444             cpuUpdateRevision = static_cast<int>(updateRevision[1]);
3445             break;
3446           } else if (vtype == REG_DWORD && len == sizeof(updateRevision[0])) {
3447             cpuUpdateRevision = static_cast<int>(updateRevision[0]);
3448             break;
3449           }
3450         }
3451       }
3452     }
3453 
3454 #ifdef MOZ_CRASHREPORTER
3455     if (cpuUpdateRevision > 0) {
3456       CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("CPUMicrocodeVersion"),
3457                                          nsPrintfCString("0x%x",
3458                                                          cpuUpdateRevision));
3459     }
3460 #endif
3461   }
3462 #endif
3463 
3464 #ifdef MOZ_CRASHREPORTER
3465     CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("SafeMode"),
3466                                        gSafeMode ? NS_LITERAL_CSTRING("1") :
3467                                                    NS_LITERAL_CSTRING("0"));
3468 #endif
3469 
3470   // Handle --no-remote and --new-instance command line arguments. Setup
3471   // the environment to better accommodate other components and various
3472   // restart scenarios.
3473   ar = CheckArg("no-remote", true);
3474   if (ar == ARG_BAD) {
3475     PR_fprintf(PR_STDERR, "Error: argument --no-remote is invalid when argument --osint is specified\n");
3476     return 1;
3477   } else if (ar == ARG_FOUND) {
3478     SaveToEnv("MOZ_NO_REMOTE=1");
3479   }
3480 
3481   ar = CheckArg("new-instance", true);
3482   if (ar == ARG_BAD) {
3483     PR_fprintf(PR_STDERR, "Error: argument --new-instance is invalid when argument --osint is specified\n");
3484     return 1;
3485   } else if (ar == ARG_FOUND) {
3486     SaveToEnv("MOZ_NEW_INSTANCE=1");
3487   }
3488 
3489   // Handle --help and --version command line arguments.
3490   // They should return quickly, so we deal with them here.
3491   if (CheckArg("h") || CheckArg("help") || CheckArg("?")) {
3492     DumpHelp();
3493     *aExitFlag = true;
3494     return 0;
3495   }
3496 
3497   if (CheckArg("v") || CheckArg("version")) {
3498     DumpVersion();
3499     *aExitFlag = true;
3500     return 0;
3501   }
3502 
3503   rv = XRE_InitCommandLine(gArgc, gArgv);
3504   NS_ENSURE_SUCCESS(rv, 1);
3505 
3506   // Check for --register, which registers chrome and then exits immediately.
3507   ar = CheckArg("register", true);
3508   if (ar == ARG_BAD) {
3509     PR_fprintf(PR_STDERR, "Error: argument --register is invalid when argument --osint is specified\n");
3510     return 1;
3511   } else if (ar == ARG_FOUND) {
3512     ScopedXPCOMStartup xpcom;
3513     rv = xpcom.Initialize();
3514     NS_ENSURE_SUCCESS(rv, 1);
3515     {
3516       nsCOMPtr<nsIChromeRegistry> chromeReg =
3517         mozilla::services::GetChromeRegistryService();
3518       NS_ENSURE_TRUE(chromeReg, 1);
3519 
3520       chromeReg->CheckForNewChrome();
3521     }
3522     *aExitFlag = true;
3523     return 0;
3524   }
3525 
3526   return 0;
3527 }
3528 
3529 #ifdef MOZ_CRASHREPORTER
3530 #ifdef XP_WIN
3531 /**
3532  * Uses WMI to read some manufacturer information that may be useful for
3533  * diagnosing hardware-specific crashes. This function is best-effort; failures
3534  * shouldn't burden the caller. COM must be initialized before calling.
3535  */
AnnotateSystemManufacturer()3536 static void AnnotateSystemManufacturer()
3537 {
3538   RefPtr<IWbemLocator> locator;
3539 
3540   HRESULT hr = CoCreateInstance(CLSID_WbemLocator, nullptr, CLSCTX_INPROC_SERVER,
3541                                 IID_IWbemLocator, getter_AddRefs(locator));
3542 
3543   if (FAILED(hr)) {
3544     return;
3545   }
3546 
3547   RefPtr<IWbemServices> services;
3548 
3549   hr = locator->ConnectServer(_bstr_t(L"ROOT\\CIMV2"), nullptr, nullptr, nullptr,
3550                               0, nullptr, nullptr, getter_AddRefs(services));
3551 
3552   if (FAILED(hr)) {
3553     return;
3554   }
3555 
3556   hr = CoSetProxyBlanket(services, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, nullptr,
3557                          RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE,
3558                          nullptr, EOAC_NONE);
3559 
3560   if (FAILED(hr)) {
3561     return;
3562   }
3563 
3564   RefPtr<IEnumWbemClassObject> enumerator;
3565 
3566   hr = services->ExecQuery(_bstr_t(L"WQL"), _bstr_t(L"SELECT * FROM Win32_BIOS"),
3567                            WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
3568                            nullptr, getter_AddRefs(enumerator));
3569 
3570   if (FAILED(hr) || !enumerator) {
3571     return;
3572   }
3573 
3574   RefPtr<IWbemClassObject> classObject;
3575   ULONG results;
3576 
3577   hr = enumerator->Next(WBEM_INFINITE, 1, getter_AddRefs(classObject), &results);
3578 
3579   if (FAILED(hr) || results == 0) {
3580     return;
3581   }
3582 
3583   VARIANT value;
3584   VariantInit(&value);
3585 
3586   hr = classObject->Get(L"Manufacturer", 0, &value, 0, 0);
3587 
3588   if (SUCCEEDED(hr) && V_VT(&value) == VT_BSTR) {
3589     CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("BIOS_Manufacturer"),
3590                                        NS_ConvertUTF16toUTF8(V_BSTR(&value)));
3591   }
3592 
3593   VariantClear(&value);
3594 }
3595 
AnnotateSystemManufacturer_ThreadStart(void *)3596 static void PR_CALLBACK AnnotateSystemManufacturer_ThreadStart(void*)
3597 {
3598   HRESULT hr = CoInitialize(nullptr);
3599 
3600   if (FAILED(hr)) {
3601     return;
3602   }
3603 
3604   AnnotateSystemManufacturer();
3605 
3606   CoUninitialize();
3607 }
3608 #endif // XP_WIN
3609 
3610 #if defined(XP_LINUX) && !defined(ANDROID)
3611 
3612 static void
AnnotateLSBRelease(void *)3613 AnnotateLSBRelease(void*)
3614 {
3615   nsCString dist, desc, release, codename;
3616   if (widget::lsb::GetLSBRelease(dist, desc, release, codename)) {
3617     CrashReporter::AppendAppNotesToCrashReport(desc);
3618   }
3619 }
3620 
3621 #endif // defined(XP_LINUX) && !defined(ANDROID)
3622 
3623 #endif
3624 
3625 namespace mozilla {
3626   ShutdownChecksMode gShutdownChecks = SCM_NOTHING;
3627 } // namespace mozilla
3628 
SetShutdownChecks()3629 static void SetShutdownChecks() {
3630   // Set default first. On debug builds we crash. On nightly and local
3631   // builds we record. Nightlies will then send the info via telemetry,
3632   // but it is usefull to have the data in about:telemetry in local builds
3633   // too.
3634 
3635 #ifdef DEBUG
3636   gShutdownChecks = SCM_CRASH;
3637 #else
3638   const char* releaseChannel = NS_STRINGIFY(MOZ_UPDATE_CHANNEL);
3639   if (strcmp(releaseChannel, "nightly") == 0 ||
3640       strcmp(releaseChannel, "default") == 0) {
3641     gShutdownChecks = SCM_RECORD;
3642   } else {
3643     gShutdownChecks = SCM_NOTHING;
3644   }
3645 #endif
3646 
3647   // We let an environment variable override the default so that addons
3648   // authors can use it for debugging shutdown with released firefox versions.
3649   const char* mozShutdownChecksEnv = PR_GetEnv("MOZ_SHUTDOWN_CHECKS");
3650   if (mozShutdownChecksEnv) {
3651     if (strcmp(mozShutdownChecksEnv, "crash") == 0) {
3652       gShutdownChecks = SCM_CRASH;
3653     } else if (strcmp(mozShutdownChecksEnv, "record") == 0) {
3654       gShutdownChecks = SCM_RECORD;
3655     } else if (strcmp(mozShutdownChecksEnv, "nothing") == 0) {
3656       gShutdownChecks = SCM_NOTHING;
3657     }
3658   }
3659 
3660 }
3661 
3662 /*
3663  * XRE_mainStartup - Initializes the profile and various other services.
3664  * Main() will exit early if either return value != 0 or if aExitFlag is
3665  * true.
3666  */
3667 int
XRE_mainStartup(bool * aExitFlag)3668 XREMain::XRE_mainStartup(bool* aExitFlag)
3669 {
3670   nsresult rv;
3671 
3672   if (!aExitFlag)
3673     return 1;
3674   *aExitFlag = false;
3675 
3676   SetShutdownChecks();
3677 
3678   // Enable Telemetry IO Reporting on DEBUG, nightly and local builds
3679 #ifdef DEBUG
3680   mozilla::Telemetry::InitIOReporting(gAppData->xreDirectory);
3681 #else
3682   {
3683     const char* releaseChannel = NS_STRINGIFY(MOZ_UPDATE_CHANNEL);
3684     if (strcmp(releaseChannel, "nightly") == 0 ||
3685         strcmp(releaseChannel, "default") == 0) {
3686       mozilla::Telemetry::InitIOReporting(gAppData->xreDirectory);
3687     }
3688   }
3689 #endif /* DEBUG */
3690 
3691 #if defined(MOZ_WIDGET_GTK) || defined(MOZ_ENABLE_XREMOTE)
3692   // Stash DESKTOP_STARTUP_ID in malloc'ed memory because gtk_init will clear it.
3693 #define HAVE_DESKTOP_STARTUP_ID
3694   const char* desktopStartupIDEnv = PR_GetEnv("DESKTOP_STARTUP_ID");
3695   if (desktopStartupIDEnv) {
3696     mDesktopStartupID.Assign(desktopStartupIDEnv);
3697   }
3698 #endif
3699 
3700 #if defined(MOZ_WIDGET_GTK)
3701   // setup for private colormap.  Ideally we'd like to do this
3702   // in nsAppShell::Create, but we need to get in before gtk
3703   // has been initialized to make sure everything is running
3704   // consistently.
3705 #if (MOZ_WIDGET_GTK == 2)
3706   if (CheckArg("install"))
3707     gdk_rgb_set_install(TRUE);
3708 #endif
3709 
3710   // Set program name to the one defined in application.ini.
3711   {
3712     nsAutoCString program(gAppData->name);
3713     ToLowerCase(program);
3714     g_set_prgname(program.get());
3715   }
3716 
3717   // Initialize GTK here for splash.
3718 
3719 #if (MOZ_WIDGET_GTK == 3) && defined(MOZ_X11)
3720   // Disable XInput2 support due to focus bugginess. See bugs 1182700, 1170342.
3721   const char* useXI2 = PR_GetEnv("MOZ_USE_XINPUT2");
3722   if (!useXI2 || (*useXI2 == '0'))
3723     gdk_disable_multidevice();
3724 #endif
3725 
3726   // Open the display ourselves instead of using gtk_init, so that we can
3727   // close it without fear that one day gtk might clean up the display it
3728   // opens.
3729   if (!gtk_parse_args(&gArgc, &gArgv))
3730     return 1;
3731 #endif /* MOZ_WIDGET_GTK */
3732 
3733 #ifdef LIBFUZZER
3734   if (PR_GetEnv("LIBFUZZER")) {
3735     *aExitFlag = true;
3736     return mozilla::libFuzzerRunner->Run();
3737   }
3738 #endif
3739 
3740   if (PR_GetEnv("MOZ_RUN_GTEST")) {
3741     int result;
3742 #ifdef XP_WIN
3743     UseParentConsole();
3744 #endif
3745     // RunGTest will only be set if we're in xul-unit
3746     if (mozilla::RunGTest) {
3747       gIsGtest = true;
3748       result = mozilla::RunGTest();
3749       gIsGtest = false;
3750     } else {
3751       result = 1;
3752       printf("TEST-UNEXPECTED-FAIL | gtest | Not compiled with enable-tests\n");
3753     }
3754     *aExitFlag = true;
3755     return result;
3756   }
3757 
3758 #if defined(MOZ_WIDGET_GTK)
3759   // display_name is owned by gdk.
3760   const char *display_name = gdk_get_display_arg_name();
3761   bool saveDisplayArg = false;
3762   if (display_name) {
3763     saveDisplayArg = true;
3764   } else {
3765     display_name = detectDisplay();
3766     if (!display_name) {
3767       return 1;
3768     }
3769   }
3770 #endif /* MOZ_WIDGET_GTK */
3771 #ifdef MOZ_X11
3772   // Init X11 in thread-safe mode. Must be called prior to the first call to XOpenDisplay
3773   // (called inside gdk_display_open). This is a requirement for off main tread compositing.
3774   XInitThreads();
3775 #endif
3776 #if defined(MOZ_WIDGET_GTK)
3777   mGdkDisplay = gdk_display_open(display_name);
3778   if (!mGdkDisplay) {
3779     PR_fprintf(PR_STDERR, "Error: cannot open display: %s\n", display_name);
3780     return 1;
3781   }
3782   gdk_display_manager_set_default_display (gdk_display_manager_get(),
3783                                            mGdkDisplay);
3784   if (GDK_IS_X11_DISPLAY(mGdkDisplay)) {
3785     if (saveDisplayArg) {
3786       SaveWordToEnv("DISPLAY", nsDependentCString(display_name));
3787     }
3788   } else {
3789     mDisableRemote = true;
3790   }
3791 #endif
3792 #ifdef MOZ_ENABLE_XREMOTE
3793   // handle --remote now that xpcom is fired up
3794   bool newInstance;
3795   {
3796     char *e = PR_GetEnv("MOZ_NO_REMOTE");
3797     mDisableRemote = (mDisableRemote || (e && *e));
3798     if (mDisableRemote) {
3799       newInstance = true;
3800     } else {
3801       e = PR_GetEnv("MOZ_NEW_INSTANCE");
3802       newInstance = (e && *e);
3803     }
3804   }
3805 
3806   if (!newInstance) {
3807     nsAutoCString program(gAppData->remotingName);
3808     ToLowerCase(program);
3809 
3810     const char* username = getenv("LOGNAME");
3811     const char* profile  = nullptr;
3812 
3813     RemoteResult rr = ParseRemoteCommandLine(program, &profile, &username);
3814     if (rr == REMOTE_ARG_BAD) {
3815       return 1;
3816     }
3817 
3818     if (!username) {
3819       struct passwd *pw = getpwuid(geteuid());
3820       if (pw && pw->pw_name) {
3821         // Beware that another call to getpwent/getpwname/getpwuid will overwrite
3822         // pw, but we don't have such another call between here and when username
3823         // is used last.
3824         username = pw->pw_name;
3825       }
3826     }
3827 
3828     nsCOMPtr<nsIFile> mutexDir;
3829     rv = GetSpecialSystemDirectory(OS_TemporaryDirectory, getter_AddRefs(mutexDir));
3830     if (NS_SUCCEEDED(rv)) {
3831       nsAutoCString mutexPath = program + NS_LITERAL_CSTRING("_");
3832       // In the unlikely even that LOGNAME is not set and getpwuid failed, just
3833       // don't put the username in the mutex directory. It will conflict with
3834       // other users mutex, but the worst that can happen is that they wait for
3835       // MOZ_XREMOTE_START_TIMEOUT_SEC during startup in that case.
3836       if (username) {
3837         mutexPath.Append(username);
3838       }
3839       if (profile) {
3840         mutexPath.Append(NS_LITERAL_CSTRING("_") + nsDependentCString(profile));
3841       }
3842       mutexDir->AppendNative(mutexPath);
3843 
3844       rv = mutexDir->Create(nsIFile::DIRECTORY_TYPE, 0700);
3845       if (NS_SUCCEEDED(rv) || rv == NS_ERROR_FILE_ALREADY_EXISTS) {
3846         mRemoteLockDir = mutexDir;
3847       }
3848     }
3849 
3850     if (mRemoteLockDir) {
3851       const TimeStamp epoch = mozilla::TimeStamp::Now();
3852       do {
3853         rv = mRemoteLock.Lock(mRemoteLockDir, nullptr);
3854         if (NS_SUCCEEDED(rv))
3855           break;
3856         sched_yield();
3857       } while ((TimeStamp::Now() - epoch)
3858                < TimeDuration::FromSeconds(MOZ_XREMOTE_START_TIMEOUT_SEC));
3859       if (NS_FAILED(rv)) {
3860         NS_WARNING("Cannot lock XRemote start mutex");
3861       }
3862     }
3863 
3864     // Try to remote the entire command line. If this fails, start up normally.
3865     const char* desktopStartupIDPtr =
3866       mDesktopStartupID.IsEmpty() ? nullptr : mDesktopStartupID.get();
3867 
3868     rr = StartRemoteClient(desktopStartupIDPtr, program, profile, username);
3869     if (rr == REMOTE_FOUND) {
3870       *aExitFlag = true;
3871       return 0;
3872     } else if (rr == REMOTE_ARG_BAD) {
3873       return 1;
3874     }
3875   }
3876 #endif
3877 #if defined(MOZ_WIDGET_GTK)
3878   g_set_application_name(mAppData->name);
3879   gtk_window_set_auto_startup_notification(false);
3880 
3881 #if (MOZ_WIDGET_GTK == 2)
3882   gtk_widget_set_default_colormap(gdk_rgb_get_colormap());
3883 #endif /* (MOZ_WIDGET_GTK == 2) */
3884 #endif /* defined(MOZ_WIDGET_GTK) */
3885 #ifdef MOZ_X11
3886   // Do this after initializing GDK, or GDK will install its own handler.
3887   XRE_InstallX11ErrorHandler();
3888 #endif
3889 
3890   // Call the code to install our handler
3891 #ifdef MOZ_JPROF
3892   setupProfilingStuff();
3893 #endif
3894 
3895   rv = NS_CreateNativeAppSupport(getter_AddRefs(mNativeApp));
3896   if (NS_FAILED(rv))
3897     return 1;
3898 
3899   bool canRun = false;
3900   rv = mNativeApp->Start(&canRun);
3901   if (NS_FAILED(rv) || !canRun) {
3902     return 1;
3903   }
3904 
3905 #if defined(HAVE_DESKTOP_STARTUP_ID) && defined(MOZ_WIDGET_GTK)
3906   // DESKTOP_STARTUP_ID is cleared now,
3907   // we recover it in case we need a restart.
3908   if (!mDesktopStartupID.IsEmpty()) {
3909     nsAutoCString desktopStartupEnv;
3910     desktopStartupEnv.AssignLiteral("DESKTOP_STARTUP_ID=");
3911     desktopStartupEnv.Append(mDesktopStartupID);
3912     // Leak it with extreme prejudice!
3913     PR_SetEnv(ToNewCString(desktopStartupEnv));
3914   }
3915 #endif
3916 
3917 #if defined(MOZ_UPDATER) && !defined(MOZ_WIDGET_ANDROID)
3918   // Check for and process any available updates
3919   nsCOMPtr<nsIFile> updRoot;
3920   bool persistent;
3921   rv = mDirProvider.GetFile(XRE_UPDATE_ROOT_DIR, &persistent,
3922                             getter_AddRefs(updRoot));
3923   // XRE_UPDATE_ROOT_DIR may fail. Fallback to appDir if failed
3924   if (NS_FAILED(rv))
3925     updRoot = mDirProvider.GetAppDir();
3926 
3927   // If the MOZ_TEST_PROCESS_UPDATES environment variable already exists, then
3928   // we are being called from the callback application.
3929   if (EnvHasValue("MOZ_TEST_PROCESS_UPDATES")) {
3930     // If the caller has asked us to log our arguments, do so.  This is used
3931     // to make sure that the maintenance service successfully launches the
3932     // callback application.
3933     const char *logFile = nullptr;
3934     if (ARG_FOUND == CheckArg("dump-args", false, &logFile)) {
3935       FILE* logFP = fopen(logFile, "wb");
3936       if (logFP) {
3937         for (int i = 1; i < gRestartArgc; ++i) {
3938           fprintf(logFP, "%s\n", gRestartArgv[i]);
3939         }
3940         fclose(logFP);
3941       }
3942     }
3943     *aExitFlag = true;
3944     return 0;
3945   }
3946 
3947   // Support for processing an update and exiting. The MOZ_TEST_PROCESS_UPDATES
3948   // environment variable will be part of the updater's environment and the
3949   // application that is relaunched by the updater. When the application is
3950   // relaunched by the updater it will be removed below and the application
3951   // will exit.
3952   if (CheckArg("test-process-updates")) {
3953     SaveToEnv("MOZ_TEST_PROCESS_UPDATES=1");
3954   }
3955   nsCOMPtr<nsIFile> exeFile, exeDir;
3956   rv = mDirProvider.GetFile(XRE_EXECUTABLE_FILE, &persistent,
3957                             getter_AddRefs(exeFile));
3958   NS_ENSURE_SUCCESS(rv, 1);
3959   rv = exeFile->GetParent(getter_AddRefs(exeDir));
3960   NS_ENSURE_SUCCESS(rv, 1);
3961   ProcessUpdates(mDirProvider.GetGREDir(),
3962                  exeDir,
3963                  updRoot,
3964                  gRestartArgc,
3965                  gRestartArgv,
3966                  mAppData->version);
3967   if (EnvHasValue("MOZ_TEST_PROCESS_UPDATES")) {
3968     SaveToEnv("MOZ_TEST_PROCESS_UPDATES=");
3969     *aExitFlag = true;
3970     return 0;
3971   }
3972 #endif
3973 
3974   rv = NS_NewToolkitProfileService(getter_AddRefs(mProfileSvc));
3975   if (rv == NS_ERROR_FILE_ACCESS_DENIED) {
3976     PR_fprintf(PR_STDERR, "Error: Access was denied while trying to open files in " \
3977                 "your profile directory.\n");
3978   }
3979   if (NS_FAILED(rv)) {
3980     // We failed to choose or create profile - notify user and quit
3981     ProfileMissingDialog(mNativeApp);
3982     return 1;
3983   }
3984 
3985   rv = SelectProfile(getter_AddRefs(mProfileLock), mProfileSvc, mNativeApp, &mStartOffline,
3986                       &mProfileName);
3987   if (rv == NS_ERROR_LAUNCHED_CHILD_PROCESS ||
3988       rv == NS_ERROR_ABORT) {
3989     *aExitFlag = true;
3990     return 0;
3991   }
3992 
3993   if (NS_FAILED(rv)) {
3994     // We failed to choose or create profile - notify user and quit
3995     ProfileMissingDialog(mNativeApp);
3996     return 1;
3997   }
3998   gProfileLock = mProfileLock;
3999 
4000   rv = mProfileLock->GetDirectory(getter_AddRefs(mProfD));
4001   NS_ENSURE_SUCCESS(rv, 1);
4002 
4003   rv = mProfileLock->GetLocalDirectory(getter_AddRefs(mProfLD));
4004   NS_ENSURE_SUCCESS(rv, 1);
4005 
4006   rv = mDirProvider.SetProfile(mProfD, mProfLD);
4007   NS_ENSURE_SUCCESS(rv, 1);
4008 
4009   //////////////////////// NOW WE HAVE A PROFILE ////////////////////////
4010 
4011   mozilla::Telemetry::SetProfileDir(mProfD);
4012 
4013 #ifdef MOZ_CRASHREPORTER
4014   if (mAppData->flags & NS_XRE_ENABLE_CRASH_REPORTER)
4015       MakeOrSetMinidumpPath(mProfD);
4016 
4017   CrashReporter::SetProfileDirectory(mProfD);
4018 #endif
4019 
4020   nsAutoCString version;
4021   BuildVersion(version);
4022 
4023 #ifdef TARGET_OS_ABI
4024   NS_NAMED_LITERAL_CSTRING(osABI, TARGET_OS_ABI);
4025 #else
4026   // No TARGET_XPCOM_ABI, but at least the OS is known
4027   NS_NAMED_LITERAL_CSTRING(osABI, OS_TARGET "_UNKNOWN");
4028 #endif
4029 
4030   // Check for version compatibility with the last version of the app this
4031   // profile was started with.  The format of the version stamp is defined
4032   // by the BuildVersion function.
4033   // Also check to see if something has happened to invalidate our
4034   // fastload caches, like an extension upgrade or installation.
4035 
4036   // If we see .purgecaches, that means someone did a make.
4037   // Re-register components to catch potential changes.
4038   nsCOMPtr<nsIFile> flagFile;
4039 
4040   rv = NS_ERROR_FILE_NOT_FOUND;
4041   nsCOMPtr<nsIFile> fFlagFile;
4042   if (mAppData->directory) {
4043     rv = mAppData->directory->Clone(getter_AddRefs(fFlagFile));
4044   }
4045   flagFile = do_QueryInterface(fFlagFile);
4046   if (flagFile) {
4047     flagFile->AppendNative(FILE_INVALIDATE_CACHES);
4048   }
4049 
4050   bool cachesOK;
4051   bool versionOK = CheckCompatibility(mProfD, version, osABI,
4052                                       mDirProvider.GetGREDir(),
4053                                       mAppData->directory, flagFile,
4054                                       &cachesOK);
4055   if (CheckArg("purgecaches")) {
4056     cachesOK = false;
4057   }
4058   if (PR_GetEnv("MOZ_PURGE_CACHES")) {
4059     cachesOK = false;
4060   }
4061 
4062   // Every time a profile is loaded by a build with a different version,
4063   // it updates the compatibility.ini file saying what version last wrote
4064   // the fastload caches.  On subsequent launches if the version matches,
4065   // there is no need for re-registration.  If the user loads the same
4066   // profile in different builds the component registry must be
4067   // re-generated to prevent mysterious component loading failures.
4068   //
4069   bool startupCacheValid = true;
4070   if (gSafeMode) {
4071     startupCacheValid = RemoveComponentRegistries(mProfD, mProfLD, false);
4072     WriteVersion(mProfD, NS_LITERAL_CSTRING("Safe Mode"), osABI,
4073                  mDirProvider.GetGREDir(), mAppData->directory, !startupCacheValid);
4074   }
4075   else if (versionOK) {
4076     if (!cachesOK) {
4077       // Remove caches, forcing component re-registration.
4078       // The new list of additional components directories is derived from
4079       // information in "extensions.ini".
4080       startupCacheValid = RemoveComponentRegistries(mProfD, mProfLD, false);
4081 
4082       // Rewrite compatibility.ini to remove the flag
4083       WriteVersion(mProfD, version, osABI,
4084                    mDirProvider.GetGREDir(), mAppData->directory, !startupCacheValid);
4085     }
4086     // Nothing need be done for the normal startup case.
4087   }
4088   else {
4089     // Remove caches, forcing component re-registration
4090     // with the default set of components (this disables any potentially
4091     // troublesome incompatible XPCOM components).
4092     startupCacheValid = RemoveComponentRegistries(mProfD, mProfLD, true);
4093 
4094     // Write out version
4095     WriteVersion(mProfD, version, osABI,
4096                  mDirProvider.GetGREDir(), mAppData->directory, !startupCacheValid);
4097   }
4098 
4099   if (!startupCacheValid)
4100     StartupCache::IgnoreDiskCache();
4101 
4102   if (flagFile) {
4103     flagFile->Remove(true);
4104   }
4105 
4106   return 0;
4107 }
4108 
4109 #if defined(MOZ_CRASHREPORTER)
4110 #if defined(MOZ_CONTENT_SANDBOX) && !defined(MOZ_WIDGET_GONK)
AddSandboxAnnotations()4111 void AddSandboxAnnotations()
4112 {
4113   // Include the sandbox content level, regardless of platform
4114   int level = Preferences::GetInt("security.sandbox.content.level");
4115 
4116   nsAutoCString levelString;
4117   levelString.AppendInt(level);
4118 
4119   CrashReporter::AnnotateCrashReport(
4120     NS_LITERAL_CSTRING("ContentSandboxLevel"), levelString);
4121 
4122   // Include whether or not this instance is capable of content sandboxing
4123   bool sandboxCapable = false;
4124 
4125 #if defined(XP_WIN)
4126   // All supported Windows versions support some level of content sandboxing
4127   sandboxCapable = true;
4128 #elif defined(XP_MACOSX)
4129   // All supported OS X versions are capable
4130   sandboxCapable = true;
4131 #elif defined(XP_LINUX)
4132   sandboxCapable = SandboxInfo::Get().CanSandboxContent();
4133 #endif
4134 
4135   CrashReporter::AnnotateCrashReport(
4136     NS_LITERAL_CSTRING("ContentSandboxCapable"),
4137     sandboxCapable ? NS_LITERAL_CSTRING("1") : NS_LITERAL_CSTRING("0"));
4138 }
4139 #endif /* MOZ_CONTENT_SANDBOX && !MOZ_WIDGET_GONK */
4140 #endif /* MOZ_CRASHREPORTER */
4141 
4142 /*
4143  * XRE_mainRun - Command line startup, profile migration, and
4144  * the calling of appStartup->Run().
4145  */
4146 nsresult
XRE_mainRun()4147 XREMain::XRE_mainRun()
4148 {
4149   nsresult rv = NS_OK;
4150   NS_ASSERTION(mScopedXPCOM, "Scoped xpcom not initialized.");
4151 
4152 #ifdef NS_FUNCTION_TIMER
4153   // initialize some common services, so we don't pay the cost for these at odd times later on;
4154   // SetWindowCreator -> ChromeRegistry -> IOService -> SocketTransportService -> (nspr wspm init), Prefs
4155   {
4156     nsCOMPtr<nsISupports> comp;
4157 
4158     comp = do_GetService("@mozilla.org/preferences-service;1");
4159 
4160     comp = do_GetService("@mozilla.org/network/socket-transport-service;1");
4161 
4162     comp = do_GetService("@mozilla.org/network/dns-service;1");
4163 
4164     comp = do_GetService("@mozilla.org/network/io-service;1");
4165 
4166     comp = do_GetService("@mozilla.org/chrome/chrome-registry;1");
4167 
4168     comp = do_GetService("@mozilla.org/focus-event-suppressor-service;1");
4169   }
4170 #endif
4171 
4172   rv = mScopedXPCOM->SetWindowCreator(mNativeApp);
4173   NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
4174 
4175 #ifdef MOZ_CRASHREPORTER
4176   // tell the crash reporter to also send the release channel
4177   nsCOMPtr<nsIPrefService> prefs = do_GetService("@mozilla.org/preferences-service;1", &rv);
4178   if (NS_SUCCEEDED(rv)) {
4179     nsCOMPtr<nsIPrefBranch> defaultPrefBranch;
4180     rv = prefs->GetDefaultBranch(nullptr, getter_AddRefs(defaultPrefBranch));
4181 
4182     if (NS_SUCCEEDED(rv)) {
4183       nsXPIDLCString sval;
4184       rv = defaultPrefBranch->GetCharPref("app.update.channel", getter_Copies(sval));
4185       if (NS_SUCCEEDED(rv)) {
4186         CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("ReleaseChannel"),
4187                                             sval);
4188       }
4189     }
4190   }
4191   // Needs to be set after xpcom initialization.
4192   CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("FramePoisonBase"),
4193                                      nsPrintfCString("%.16llx", uint64_t(gMozillaPoisonBase)));
4194   CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("FramePoisonSize"),
4195                                      nsPrintfCString("%lu", uint32_t(gMozillaPoisonSize)));
4196 
4197 #ifdef XP_WIN
4198   PR_CreateThread(PR_USER_THREAD, AnnotateSystemManufacturer_ThreadStart, 0,
4199                   PR_PRIORITY_LOW, PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD, 0);
4200 #endif
4201 
4202 #if defined(XP_LINUX) && !defined(ANDROID)
4203   PR_CreateThread(PR_USER_THREAD, AnnotateLSBRelease, 0, PR_PRIORITY_LOW,
4204                   PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD, 0);
4205 #endif
4206 
4207 #endif
4208 
4209   if (mStartOffline) {
4210     nsCOMPtr<nsIIOService2> io (do_GetService("@mozilla.org/network/io-service;1"));
4211     NS_ENSURE_TRUE(io, NS_ERROR_FAILURE);
4212     io->SetManageOfflineStatus(false);
4213     io->SetOffline(true);
4214   }
4215 
4216   {
4217     nsCOMPtr<nsIObserver> startupNotifier
4218       (do_CreateInstance(NS_APPSTARTUPNOTIFIER_CONTRACTID, &rv));
4219     NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
4220 
4221     startupNotifier->Observe(nullptr, APPSTARTUP_TOPIC, nullptr);
4222   }
4223 
4224   nsCOMPtr<nsIAppStartup> appStartup
4225     (do_GetService(NS_APPSTARTUP_CONTRACTID));
4226   NS_ENSURE_TRUE(appStartup, NS_ERROR_FAILURE);
4227 
4228   if (gDoMigration) {
4229     nsCOMPtr<nsIFile> file;
4230     mDirProvider.GetAppDir()->Clone(getter_AddRefs(file));
4231     file->AppendNative(NS_LITERAL_CSTRING("override.ini"));
4232     nsINIParser parser;
4233     nsresult rv = parser.Init(file);
4234     // if override.ini doesn't exist, also check for distribution.ini
4235     if (NS_FAILED(rv)) {
4236       bool persistent;
4237       mDirProvider.GetFile(XRE_APP_DISTRIBUTION_DIR, &persistent,
4238                            getter_AddRefs(file));
4239       file->AppendNative(NS_LITERAL_CSTRING("distribution.ini"));
4240       rv = parser.Init(file);
4241     }
4242     if (NS_SUCCEEDED(rv)) {
4243       nsAutoCString buf;
4244       rv = parser.GetString("XRE", "EnableProfileMigrator", buf);
4245       if (NS_SUCCEEDED(rv)) {
4246         if (buf[0] == '0' || buf[0] == 'f' || buf[0] == 'F') {
4247           gDoMigration = false;
4248         }
4249       }
4250     }
4251   }
4252 
4253   {
4254     nsCOMPtr<nsIToolkitProfile> profileBeingReset;
4255     bool profileWasSelected = false;
4256     if (gDoProfileReset) {
4257       if (gResetOldProfileName.IsEmpty()) {
4258         NS_WARNING("Not resetting profile as the profile has no name.");
4259         gDoProfileReset = false;
4260       } else {
4261         rv = mProfileSvc->GetProfileByName(gResetOldProfileName,
4262                                            getter_AddRefs(profileBeingReset));
4263         if (NS_FAILED(rv)) {
4264           gDoProfileReset = false;
4265           return NS_ERROR_FAILURE;
4266         }
4267 
4268         nsCOMPtr<nsIToolkitProfile> defaultProfile;
4269         // This can fail if there is no default profile.
4270         // That shouldn't stop reset from proceeding.
4271         nsresult gotSelected = mProfileSvc->GetSelectedProfile(getter_AddRefs(defaultProfile));
4272         if (NS_SUCCEEDED(gotSelected)) {
4273           profileWasSelected = defaultProfile == profileBeingReset;
4274         }
4275       }
4276     }
4277 
4278     // Profile Migration
4279     if (mAppData->flags & NS_XRE_ENABLE_PROFILE_MIGRATOR && gDoMigration) {
4280       gDoMigration = false;
4281       nsCOMPtr<nsIProfileMigrator> pm(do_CreateInstance(NS_PROFILEMIGRATOR_CONTRACTID));
4282       if (pm) {
4283         nsAutoCString aKey;
4284         if (gDoProfileReset) {
4285           // Automatically migrate from the current application if we just
4286           // reset the profile.
4287           aKey = MOZ_APP_NAME;
4288         }
4289         pm->Migrate(&mDirProvider, aKey, gResetOldProfileName);
4290       }
4291     }
4292 
4293     if (gDoProfileReset) {
4294       nsresult backupCreated = ProfileResetCleanup(profileBeingReset);
4295       if (NS_FAILED(backupCreated)) NS_WARNING("Could not cleanup the profile that was reset");
4296 
4297       // Set the new profile as the default after we're done cleaning up the old profile,
4298       // iff that profile was already the default
4299       if (profileWasSelected) {
4300         // this is actually "broken" - see bug 1122124
4301         rv = SetCurrentProfileAsDefault(mProfileSvc, mProfD);
4302         if (NS_FAILED(rv)) NS_WARNING("Could not set current profile as the default");
4303       }
4304       // Need to write out the fact that the profile has been removed and potentially
4305       // that the selected/default profile changed.
4306       mProfileSvc->Flush();
4307     }
4308   }
4309 
4310   mDirProvider.DoStartup();
4311 
4312   OverrideDefaultLocaleIfNeeded();
4313 
4314 #ifdef MOZ_CRASHREPORTER
4315   nsCString userAgentLocale;
4316   // Try a localized string first. This pref is always a localized string in
4317   // Fennec, and might be elsewhere, too.
4318   if (NS_SUCCEEDED(Preferences::GetLocalizedCString("general.useragent.locale", &userAgentLocale))) {
4319     CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("useragent_locale"), userAgentLocale);
4320   } else if (NS_SUCCEEDED(Preferences::GetCString("general.useragent.locale", &userAgentLocale))) {
4321     CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("useragent_locale"), userAgentLocale);
4322   }
4323 #endif
4324 
4325   appStartup->GetShuttingDown(&mShuttingDown);
4326 
4327   nsCOMPtr<nsICommandLineRunner> cmdLine;
4328 
4329   nsCOMPtr<nsIFile> workingDir;
4330   rv = NS_GetSpecialDirectory(NS_OS_CURRENT_WORKING_DIR, getter_AddRefs(workingDir));
4331   NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
4332 
4333   if (!mShuttingDown) {
4334     cmdLine = do_CreateInstance("@mozilla.org/toolkit/command-line;1");
4335     NS_ENSURE_TRUE(cmdLine, NS_ERROR_FAILURE);
4336 
4337     rv = cmdLine->Init(gArgc, gArgv, workingDir,
4338                        nsICommandLine::STATE_INITIAL_LAUNCH);
4339     NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
4340 
4341     /* Special-case services that need early access to the command
4342         line. */
4343     nsCOMPtr<nsIObserverService> obsService =
4344       mozilla::services::GetObserverService();
4345     if (obsService) {
4346       obsService->NotifyObservers(cmdLine, "command-line-startup", nullptr);
4347     }
4348   }
4349 
4350 #ifdef XP_WIN
4351   // Hack to sync up the various environment storages. XUL_APP_FILE is special
4352   // in that it comes from a different CRT (firefox.exe's static-linked copy).
4353   // Ugly details in http://bugzil.la/1175039#c27
4354   char appFile[MAX_PATH];
4355   if (GetEnvironmentVariableA("XUL_APP_FILE", appFile, sizeof(appFile))) {
4356     char* saved = PR_smprintf("XUL_APP_FILE=%s", appFile);
4357     PR_SetEnv(saved);
4358     PR_smprintf_free(saved);
4359   }
4360 #endif
4361 
4362   SaveStateForAppInitiatedRestart();
4363 
4364   // clear out any environment variables which may have been set
4365   // during the relaunch process now that we know we won't be relaunching.
4366   SaveToEnv("XRE_PROFILE_PATH=");
4367   SaveToEnv("XRE_PROFILE_LOCAL_PATH=");
4368   SaveToEnv("XRE_PROFILE_NAME=");
4369   SaveToEnv("XRE_START_OFFLINE=");
4370   SaveToEnv("NO_EM_RESTART=");
4371   SaveToEnv("XUL_APP_FILE=");
4372   SaveToEnv("XRE_BINARY_PATH=");
4373 
4374   if (!mShuttingDown) {
4375     rv = appStartup->CreateHiddenWindow();
4376     NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
4377 
4378 #ifdef MOZ_STYLO
4379     // We initialize Servo here so that the hidden DOM window is available,
4380     // since initializing Servo calls style struct constructors, and the
4381     // HackilyFindDeviceContext stuff we have right now depends on the hidden
4382     // DOM window. When we fix that, this should move back to
4383     // nsLayoutStatics.cpp
4384     Servo_Initialize();
4385 #endif
4386 
4387 #if defined(HAVE_DESKTOP_STARTUP_ID) && defined(MOZ_WIDGET_GTK)
4388     nsGTKToolkit* toolkit = nsGTKToolkit::GetToolkit();
4389     if (toolkit && !mDesktopStartupID.IsEmpty()) {
4390       toolkit->SetDesktopStartupID(mDesktopStartupID);
4391     }
4392     // Clear the environment variable so it won't be inherited by
4393     // child processes and confuse things.
4394     g_unsetenv ("DESKTOP_STARTUP_ID");
4395 #endif
4396 
4397 #ifdef XP_MACOSX
4398     // we re-initialize the command-line service and do appleevents munging
4399     // after we are sure that we're not restarting
4400     cmdLine = do_CreateInstance("@mozilla.org/toolkit/command-line;1");
4401     NS_ENSURE_TRUE(cmdLine, NS_ERROR_FAILURE);
4402 
4403     CommandLineServiceMac::SetupMacCommandLine(gArgc, gArgv, false);
4404 
4405     rv = cmdLine->Init(gArgc, gArgv,
4406                         workingDir, nsICommandLine::STATE_INITIAL_LAUNCH);
4407     NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
4408 #endif
4409 
4410     nsCOMPtr<nsIObserverService> obsService =
4411       mozilla::services::GetObserverService();
4412     if (obsService)
4413       obsService->NotifyObservers(nullptr, "final-ui-startup", nullptr);
4414 
4415     (void)appStartup->DoneStartingUp();
4416 
4417 #ifdef MOZ_CRASHREPORTER
4418     CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("StartupCrash"),
4419                                        NS_LITERAL_CSTRING("0"));
4420 #endif
4421 
4422     appStartup->GetShuttingDown(&mShuttingDown);
4423   }
4424 
4425   if (!mShuttingDown) {
4426     rv = cmdLine->Run();
4427     NS_ENSURE_SUCCESS_LOG(rv, NS_ERROR_FAILURE);
4428 
4429     appStartup->GetShuttingDown(&mShuttingDown);
4430   }
4431 
4432   if (!mShuttingDown) {
4433 #ifdef MOZ_ENABLE_XREMOTE
4434     // if we have X remote support, start listening for requests on the
4435     // proxy window.
4436     if (!mDisableRemote)
4437       mRemoteService = do_GetService("@mozilla.org/toolkit/remote-service;1");
4438     if (mRemoteService)
4439       mRemoteService->Startup(mAppData->remotingName, mProfileName.get());
4440     if (mRemoteLockDir) {
4441       mRemoteLock.Unlock();
4442       mRemoteLockDir->Remove(false);
4443     }
4444 #endif /* MOZ_ENABLE_XREMOTE */
4445 
4446     mNativeApp->Enable();
4447   }
4448 
4449 #ifdef MOZ_INSTRUMENT_EVENT_LOOP
4450   if (PR_GetEnv("MOZ_INSTRUMENT_EVENT_LOOP")) {
4451     bool logToConsole = true;
4452     mozilla::InitEventTracing(logToConsole);
4453   }
4454 #endif /* MOZ_INSTRUMENT_EVENT_LOOP */
4455 
4456 #if defined(MOZ_SANDBOX) && defined(XP_LINUX) && !defined(MOZ_WIDGET_GONK)
4457   // If we're on Linux, we now have information about the OS capabilities
4458   // available to us.
4459   SandboxInfo sandboxInfo = SandboxInfo::Get();
4460   Telemetry::Accumulate(Telemetry::SANDBOX_HAS_SECCOMP_BPF,
4461                         sandboxInfo.Test(SandboxInfo::kHasSeccompBPF));
4462   Telemetry::Accumulate(Telemetry::SANDBOX_HAS_SECCOMP_TSYNC,
4463                         sandboxInfo.Test(SandboxInfo::kHasSeccompTSync));
4464   Telemetry::Accumulate(Telemetry::SANDBOX_HAS_USER_NAMESPACES_PRIVILEGED,
4465                         sandboxInfo.Test(SandboxInfo::kHasPrivilegedUserNamespaces));
4466   Telemetry::Accumulate(Telemetry::SANDBOX_HAS_USER_NAMESPACES,
4467                         sandboxInfo.Test(SandboxInfo::kHasUserNamespaces));
4468   Telemetry::Accumulate(Telemetry::SANDBOX_CONTENT_ENABLED,
4469                         sandboxInfo.Test(SandboxInfo::kEnabledForContent));
4470   Telemetry::Accumulate(Telemetry::SANDBOX_MEDIA_ENABLED,
4471                         sandboxInfo.Test(SandboxInfo::kEnabledForMedia));
4472 #if defined(MOZ_CRASHREPORTER)
4473   nsAutoCString flagsString;
4474   flagsString.AppendInt(sandboxInfo.AsInteger());
4475 
4476   CrashReporter::AnnotateCrashReport(
4477     NS_LITERAL_CSTRING("ContentSandboxCapabilities"), flagsString);
4478 #endif /* MOZ_CRASHREPORTER */
4479 #endif /* MOZ_SANDBOX && XP_LINUX && !MOZ_WIDGET_GONK */
4480 
4481 #if defined(MOZ_CRASHREPORTER)
4482 #if defined(MOZ_CONTENT_SANDBOX) && !defined(MOZ_WIDGET_GONK)
4483   AddSandboxAnnotations();
4484 #endif /* MOZ_CONTENT_SANDBOX && !MOZ_WIDGET_GONK */
4485 #endif /* MOZ_CRASHREPORTER */
4486 
4487   {
4488     rv = appStartup->Run();
4489     if (NS_FAILED(rv)) {
4490       NS_ERROR("failed to run appstartup");
4491       gLogConsoleErrors = true;
4492     }
4493   }
4494 
4495 #ifdef MOZ_STYLO
4496     // This, along with the call to Servo_Initialize, should eventually move back
4497     // to nsLayoutStatics.cpp.
4498     Servo_Shutdown();
4499 #endif
4500 
4501   return rv;
4502 }
4503 
4504 #if MOZ_WIDGET_GTK == 2
XRE_GlibInit()4505 void XRE_GlibInit()
4506 {
4507   static bool ran_once = false;
4508 
4509   // glib < 2.24 doesn't want g_thread_init to be invoked twice, so ensure
4510   // we only do it once. No need for thread safety here, since this is invoked
4511   // well before any thread is spawned.
4512   if (!ran_once) {
4513     // glib version < 2.36 doesn't initialize g_slice in a static initializer.
4514     // Ensure this happens through g_thread_init (glib version < 2.32) or
4515     // g_type_init (2.32 <= gLib version < 2.36)."
4516     g_thread_init(nullptr);
4517     g_type_init();
4518     ran_once = true;
4519   }
4520 }
4521 #endif
4522 
4523 // Separate stub function to let us specifically suppress it in Valgrind
4524 void
XRE_CreateStatsObject()4525 XRE_CreateStatsObject()
4526 {
4527   // Initialize global variables used by histogram collection
4528   // machinery that is used by by Telemetry.  Note: is never de-initialised.
4529   Telemetry::CreateStatisticsRecorder();
4530 }
4531 
4532 /*
4533  * XRE_main - A class based main entry point used by most platforms.
4534  *            Note that on OSX, aAppData->xreDirectory will point to
4535  *            .app/Contents/Resources.
4536  */
4537 int
XRE_main(int argc,char * argv[],const nsXREAppData * aAppData)4538 XREMain::XRE_main(int argc, char* argv[], const nsXREAppData* aAppData)
4539 {
4540   ScopedLogging log;
4541 
4542   // NB: this must happen after the creation of |ScopedLogging log| since
4543   // ScopedLogging::ScopedLogging calls NS_LogInit, and
4544   // XRE_CreateStatsObject calls Telemetry::CreateStatisticsRecorder,
4545   // and NS_LogInit must be called before Telemetry::CreateStatisticsRecorder.
4546   // NS_LogInit must be called before Telemetry::CreateStatisticsRecorder
4547   // so as to avoid many log messages of the form
4548   //   WARNING: XPCOM objects created/destroyed from static ctor/dtor: [..]
4549   // See bug 1279614.
4550   XRE_CreateStatsObject();
4551 
4552 #if defined(MOZ_SANDBOX) && defined(XP_LINUX) && !defined(ANDROID)
4553   SandboxInfo::ThreadingCheck();
4554 #endif
4555 
4556   char aLocal;
4557   GeckoProfilerInitRAII profilerGuard(&aLocal);
4558 
4559   PROFILER_LABEL("Startup", "XRE_Main",
4560     js::ProfileEntry::Category::OTHER);
4561 
4562   nsresult rv = NS_OK;
4563 
4564   gArgc = argc;
4565   gArgv = argv;
4566 
4567   NS_ENSURE_TRUE(aAppData, 2);
4568 
4569   mAppData = new ScopedAppData(aAppData);
4570   if (!mAppData)
4571     return 1;
4572   if (!mAppData->remotingName) {
4573     SetAllocatedString(mAppData->remotingName, mAppData->name);
4574   }
4575   // used throughout this file
4576   gAppData = mAppData;
4577 
4578   nsCOMPtr<nsIFile> binFile;
4579   rv = XRE_GetBinaryPath(argv[0], getter_AddRefs(binFile));
4580   NS_ENSURE_SUCCESS(rv, 1);
4581 
4582   rv = binFile->GetPath(gAbsoluteArgv0Path);
4583   NS_ENSURE_SUCCESS(rv, 1);
4584 
4585   mozilla::IOInterposerInit ioInterposerGuard;
4586 
4587 #if defined(XP_WIN)
4588   // Some COM settings are global to the process and must be set before any non-
4589   // trivial COM is run in the application. Since these settings may affect
4590   // stability, we should instantiate COM ASAP so that we can ensure that these
4591   // global settings are configured before anything can interfere.
4592   mozilla::mscom::MainThreadRuntime msCOMRuntime;
4593 #endif
4594 
4595 #if MOZ_WIDGET_GTK == 2
4596   XRE_GlibInit();
4597 #endif
4598 
4599   // init
4600   bool exit = false;
4601   int result = XRE_mainInit(&exit);
4602   if (result != 0 || exit)
4603     return result;
4604 
4605   // startup
4606   result = XRE_mainStartup(&exit);
4607   if (result != 0 || exit)
4608     return result;
4609 
4610   bool appInitiatedRestart = false;
4611 
4612   // Start the real application
4613   mScopedXPCOM = MakeUnique<ScopedXPCOMStartup>();
4614   if (!mScopedXPCOM)
4615     return 1;
4616 
4617   rv = mScopedXPCOM->Initialize();
4618   NS_ENSURE_SUCCESS(rv, 1);
4619 
4620   // run!
4621   rv = XRE_mainRun();
4622 
4623 #ifdef MOZ_INSTRUMENT_EVENT_LOOP
4624   mozilla::ShutdownEventTracing();
4625 #endif
4626 
4627   gAbsoluteArgv0Path.Truncate();
4628 
4629   // Check for an application initiated restart.  This is one that
4630   // corresponds to nsIAppStartup.quit(eRestart)
4631   if (rv == NS_SUCCESS_RESTART_APP
4632       || rv == NS_SUCCESS_RESTART_APP_NOT_SAME_PROFILE) {
4633     appInitiatedRestart = true;
4634 
4635     // We have an application restart don't do any shutdown checks here
4636     // In particular we don't want to poison IO for checking late-writes.
4637     gShutdownChecks = SCM_NOTHING;
4638   }
4639 
4640   if (!mShuttingDown) {
4641 #ifdef MOZ_ENABLE_XREMOTE
4642     // shut down the x remote proxy window
4643     if (mRemoteService) {
4644       mRemoteService->Shutdown();
4645     }
4646 #endif /* MOZ_ENABLE_XREMOTE */
4647   }
4648 
4649   mScopedXPCOM = nullptr;
4650 
4651 #if defined(XP_WIN)
4652   mozilla::widget::StopAudioSession();
4653 #endif
4654 
4655   // unlock the profile after ScopedXPCOMStartup object (xpcom)
4656   // has gone out of scope.  see bug #386739 for more details
4657   mProfileLock->Unlock();
4658   gProfileLock = nullptr;
4659 
4660   // Restart the app after XPCOM has been shut down cleanly.
4661   if (appInitiatedRestart) {
4662     RestoreStateForAppInitiatedRestart();
4663 
4664     if (rv != NS_SUCCESS_RESTART_APP_NOT_SAME_PROFILE) {
4665       // Ensure that these environment variables are set:
4666       SaveFileToEnvIfUnset("XRE_PROFILE_PATH", mProfD);
4667       SaveFileToEnvIfUnset("XRE_PROFILE_LOCAL_PATH", mProfLD);
4668       SaveWordToEnvIfUnset("XRE_PROFILE_NAME", mProfileName);
4669     }
4670 
4671 #ifdef MOZ_WIDGET_GTK
4672     MOZ_gdk_display_close(mGdkDisplay);
4673 #endif
4674 
4675     {
4676       rv = LaunchChild(mNativeApp, true);
4677     }
4678 
4679 #ifdef MOZ_CRASHREPORTER
4680     if (mAppData->flags & NS_XRE_ENABLE_CRASH_REPORTER)
4681       CrashReporter::UnsetExceptionHandler();
4682 #endif
4683     return rv == NS_ERROR_LAUNCHED_CHILD_PROCESS ? 0 : 1;
4684   }
4685 
4686 #ifdef MOZ_WIDGET_GTK
4687   // gdk_display_close also calls gdk_display_manager_set_default_display
4688   // appropriately when necessary.
4689   MOZ_gdk_display_close(mGdkDisplay);
4690 #endif
4691 
4692 #ifdef MOZ_CRASHREPORTER
4693   if (mAppData->flags & NS_XRE_ENABLE_CRASH_REPORTER)
4694       CrashReporter::UnsetExceptionHandler();
4695 #endif
4696 
4697   XRE_DeinitCommandLine();
4698 
4699   return NS_FAILED(rv) ? 1 : 0;
4700 }
4701 
4702 void
XRE_StopLateWriteChecks(void)4703 XRE_StopLateWriteChecks(void) {
4704   mozilla::StopLateWriteChecks();
4705 }
4706 
4707 int
XRE_main(int argc,char * argv[],const nsXREAppData * aAppData,uint32_t aFlags)4708 XRE_main(int argc, char* argv[], const nsXREAppData* aAppData, uint32_t aFlags)
4709 {
4710   XREMain main;
4711 
4712   int result = main.XRE_main(argc, argv, aAppData);
4713   mozilla::RecordShutdownEndTimeStamp();
4714   return result;
4715 }
4716 
4717 nsresult
XRE_InitCommandLine(int aArgc,char * aArgv[])4718 XRE_InitCommandLine(int aArgc, char* aArgv[])
4719 {
4720   nsresult rv = NS_OK;
4721 
4722 #if defined(OS_WIN)
4723   CommandLine::Init(aArgc, aArgv);
4724 #else
4725 
4726   // these leak on error, but that's OK: we'll just exit()
4727   char** canonArgs = new char*[aArgc];
4728 
4729   // get the canonical version of the binary's path
4730   nsCOMPtr<nsIFile> binFile;
4731   rv = XRE_GetBinaryPath(aArgv[0], getter_AddRefs(binFile));
4732   if (NS_FAILED(rv))
4733     return NS_ERROR_FAILURE;
4734 
4735   nsAutoCString canonBinPath;
4736   rv = binFile->GetNativePath(canonBinPath);
4737   if (NS_FAILED(rv))
4738     return NS_ERROR_FAILURE;
4739 
4740   canonArgs[0] = strdup(canonBinPath.get());
4741 
4742   for (int i = 1; i < aArgc; ++i) {
4743     if (aArgv[i]) {
4744       canonArgs[i] = strdup(aArgv[i]);
4745     }
4746   }
4747 
4748   NS_ASSERTION(!CommandLine::IsInitialized(), "Bad news!");
4749   CommandLine::Init(aArgc, canonArgs);
4750 
4751   for (int i = 0; i < aArgc; ++i)
4752       free(canonArgs[i]);
4753   delete[] canonArgs;
4754 #endif
4755 
4756   const char *path = nullptr;
4757   ArgResult ar = CheckArg("greomni", false, &path);
4758   if (ar == ARG_BAD) {
4759     PR_fprintf(PR_STDERR, "Error: argument --greomni requires a path argument\n");
4760     return NS_ERROR_FAILURE;
4761   }
4762 
4763   if (!path)
4764     return rv;
4765 
4766   nsCOMPtr<nsIFile> greOmni;
4767   rv = XRE_GetFileFromPath(path, getter_AddRefs(greOmni));
4768   if (NS_FAILED(rv)) {
4769     PR_fprintf(PR_STDERR, "Error: argument --greomni requires a valid path\n");
4770     return rv;
4771   }
4772 
4773   ar = CheckArg("appomni", false, &path);
4774   if (ar == ARG_BAD) {
4775     PR_fprintf(PR_STDERR, "Error: argument --appomni requires a path argument\n");
4776     return NS_ERROR_FAILURE;
4777   }
4778 
4779   nsCOMPtr<nsIFile> appOmni;
4780   if (path) {
4781       rv = XRE_GetFileFromPath(path, getter_AddRefs(appOmni));
4782       if (NS_FAILED(rv)) {
4783         PR_fprintf(PR_STDERR, "Error: argument --appomni requires a valid path\n");
4784         return rv;
4785       }
4786   }
4787 
4788   mozilla::Omnijar::Init(greOmni, appOmni);
4789   return rv;
4790 }
4791 
4792 nsresult
XRE_DeinitCommandLine()4793 XRE_DeinitCommandLine()
4794 {
4795   nsresult rv = NS_OK;
4796 
4797   CommandLine::Terminate();
4798 
4799   return rv;
4800 }
4801 
4802 GeckoProcessType
XRE_GetProcessType()4803 XRE_GetProcessType()
4804 {
4805   return mozilla::startup::sChildProcessType;
4806 }
4807 
4808 bool
XRE_IsGPUProcess()4809 XRE_IsGPUProcess()
4810 {
4811   return XRE_GetProcessType() == GeckoProcessType_GPU;
4812 }
4813 
4814 bool
XRE_IsParentProcess()4815 XRE_IsParentProcess()
4816 {
4817   return XRE_GetProcessType() == GeckoProcessType_Default;
4818 }
4819 
4820 bool
XRE_IsContentProcess()4821 XRE_IsContentProcess()
4822 {
4823   return XRE_GetProcessType() == GeckoProcessType_Content;
4824 }
4825 
4826 // If you add anything to this enum, please update about:support to reflect it
4827 enum {
4828   kE10sEnabledByUser = 0,
4829   kE10sEnabledByDefault = 1,
4830   kE10sDisabledByUser = 2,
4831   // kE10sDisabledInSafeMode = 3, was removed in bug 1172491.
4832   kE10sDisabledForAccessibility = 4,
4833   // kE10sDisabledForMacGfx = 5, was removed in bug 1068674.
4834   // kE10sDisabledForBidi = 6, removed in bug 1309599
4835   kE10sDisabledForAddons = 7,
4836   kE10sForceDisabled = 8,
4837   // kE10sDisabledForXPAcceleration = 9, removed in bug 1296353
4838   kE10sDisabledForOperatingSystem = 10,
4839 };
4840 
4841 const char* kAccessibilityLastRunDatePref = "accessibility.lastLoadDate";
4842 const char* kAccessibilityLoadedLastSessionPref = "accessibility.loadedInLastSession";
4843 
4844 #if defined(XP_WIN)
4845 static inline uint32_t
PRTimeToSeconds(PRTime t_usec)4846 PRTimeToSeconds(PRTime t_usec)
4847 {
4848   PRTime usec_per_sec = PR_USEC_PER_SEC;
4849   return uint32_t(t_usec /= usec_per_sec);
4850 }
4851 #endif
4852 
4853 const char* kForceEnableE10sPref = "browser.tabs.remote.force-enable";
4854 const char* kForceDisableE10sPref = "browser.tabs.remote.force-disable";
4855 
4856 uint32_t
MultiprocessBlockPolicy()4857 MultiprocessBlockPolicy() {
4858   if (gMultiprocessBlockPolicyInitialized) {
4859     return gMultiprocessBlockPolicy;
4860   }
4861   gMultiprocessBlockPolicyInitialized = true;
4862 
4863   /**
4864    * Avoids enabling e10s if there are add-ons installed.
4865    */
4866   bool addonsCanDisable = Preferences::GetBool("extensions.e10sBlocksEnabling", false);
4867   bool disabledByAddons = Preferences::GetBool("extensions.e10sBlockedByAddons", false);
4868 
4869 #ifdef MOZ_CRASHREPORTER
4870   CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("AddonsShouldHaveBlockedE10s"),
4871                                      disabledByAddons ? NS_LITERAL_CSTRING("1")
4872                                                       : NS_LITERAL_CSTRING("0"));
4873 #endif
4874 
4875   if (addonsCanDisable && disabledByAddons) {
4876     gMultiprocessBlockPolicy = kE10sDisabledForAddons;
4877     return gMultiprocessBlockPolicy;
4878   }
4879 
4880 #if defined(XP_WIN)
4881   bool disabledForA11y = false;
4882   /**
4883     * Avoids enabling e10s if accessibility has recently loaded. Performs the
4884     * following checks:
4885     * 1) Checks a pref indicating if a11y loaded in the last session. This pref
4886     * is set in nsBrowserGlue.js. If a11y was loaded in the last session we
4887     * do not enable e10s in this session.
4888     * 2) Accessibility stores a last run date (PR_IntervalNow) when it is
4889     * initialized (see nsBaseWidget.cpp). We check if this pref exists and
4890     * compare it to now. If a11y hasn't run in an extended period of time or
4891     * if the date pref does not exist we load e10s.
4892     */
4893   disabledForA11y = Preferences::GetBool(kAccessibilityLoadedLastSessionPref, false);
4894   if (!disabledForA11y  &&
4895       Preferences::HasUserValue(kAccessibilityLastRunDatePref)) {
4896     #define ONE_WEEK_IN_SECONDS (60*60*24*7)
4897     uint32_t a11yRunDate = Preferences::GetInt(kAccessibilityLastRunDatePref, 0);
4898     MOZ_ASSERT(0 != a11yRunDate);
4899     // If a11y hasn't run for a period of time, clear the pref and load e10s
4900     uint32_t now = PRTimeToSeconds(PR_Now());
4901     uint32_t difference = now - a11yRunDate;
4902     if (difference > ONE_WEEK_IN_SECONDS || !a11yRunDate) {
4903       Preferences::ClearUser(kAccessibilityLastRunDatePref);
4904     } else {
4905       disabledForA11y = true;
4906     }
4907   }
4908 
4909   if (disabledForA11y) {
4910     gMultiprocessBlockPolicy = kE10sDisabledForAccessibility;
4911     return gMultiprocessBlockPolicy;
4912   }
4913 #endif
4914 
4915   /**
4916    * Avoids enabling e10s for Windows XP users on the release channel.
4917    */
4918 #if defined(XP_WIN)
4919   if (!IsVistaOrLater()) {
4920     nsAdoptingCString channelName = Preferences::GetDefaultCString("app.update.channel");
4921     if (channelName.EqualsLiteral("release") || channelName.EqualsLiteral("esr")) {
4922       gMultiprocessBlockPolicy = kE10sDisabledForOperatingSystem;
4923       return gMultiprocessBlockPolicy;
4924     }
4925   }
4926 #endif // XP_WIN
4927 
4928   /*
4929    * None of the blocking policies matched, so e10s is allowed to run.
4930    * Cache the information and return 0, indicating success.
4931    */
4932   gMultiprocessBlockPolicy = 0;
4933   return 0;
4934 }
4935 
4936 bool
BrowserTabsRemoteAutostart()4937 mozilla::BrowserTabsRemoteAutostart()
4938 {
4939   if (gBrowserTabsRemoteAutostartInitialized) {
4940     return gBrowserTabsRemoteAutostart;
4941   }
4942   gBrowserTabsRemoteAutostartInitialized = true;
4943 
4944   // If we're in the content process, we are running E10S.
4945   if (XRE_IsContentProcess()) {
4946     gBrowserTabsRemoteAutostart = true;
4947     return gBrowserTabsRemoteAutostart;
4948   }
4949 
4950   bool optInPref = Preferences::GetBool("browser.tabs.remote.autostart", false);
4951   bool trialPref = Preferences::GetBool("browser.tabs.remote.autostart.2", false);
4952   bool prefEnabled = optInPref || trialPref;
4953   int status;
4954   if (optInPref) {
4955     status = kE10sEnabledByUser;
4956   } else if (trialPref) {
4957     status = kE10sEnabledByDefault;
4958   } else {
4959     status = kE10sDisabledByUser;
4960   }
4961 
4962   if (prefEnabled) {
4963     uint32_t blockPolicy = MultiprocessBlockPolicy();
4964     if (blockPolicy != 0) {
4965       status = blockPolicy;
4966     } else {
4967       gBrowserTabsRemoteAutostart = true;
4968     }
4969   }
4970 
4971   // Uber override pref for manual testing purposes
4972   if (Preferences::GetBool(kForceEnableE10sPref, false)) {
4973     gBrowserTabsRemoteAutostart = true;
4974     prefEnabled = true;
4975     status = kE10sEnabledByUser;
4976   }
4977 
4978   // Uber override pref for emergency blocking
4979   if (gBrowserTabsRemoteAutostart &&
4980       (Preferences::GetBool(kForceDisableE10sPref, false) ||
4981        EnvHasValue("MOZ_FORCE_DISABLE_E10S"))) {
4982     gBrowserTabsRemoteAutostart = false;
4983     status = kE10sForceDisabled;
4984   }
4985 
4986   gBrowserTabsRemoteStatus = status;
4987 
4988   mozilla::Telemetry::Accumulate(mozilla::Telemetry::E10S_STATUS, status);
4989   if (prefEnabled) {
4990     mozilla::Telemetry::Accumulate(mozilla::Telemetry::E10S_BLOCKED_FROM_RUNNING,
4991                                     !gBrowserTabsRemoteAutostart);
4992   }
4993   return gBrowserTabsRemoteAutostart;
4994 }
4995 
4996 void
SetupErrorHandling(const char * progname)4997 SetupErrorHandling(const char* progname)
4998 {
4999 #ifdef XP_WIN
5000   /* On Windows XPSP3 and Windows Vista if DEP is configured off-by-default
5001      we still want DEP protection: enable it explicitly and programmatically.
5002 
5003      This function is not available on WinXPSP2 so we dynamically load it.
5004   */
5005 
5006   HMODULE kernel32 = GetModuleHandleW(L"kernel32.dll");
5007   SetProcessDEPPolicyFunc _SetProcessDEPPolicy =
5008     (SetProcessDEPPolicyFunc) GetProcAddress(kernel32, "SetProcessDEPPolicy");
5009   if (_SetProcessDEPPolicy)
5010     _SetProcessDEPPolicy(PROCESS_DEP_ENABLE);
5011 #endif
5012 
5013 #ifdef XP_WIN32
5014   // Suppress the "DLL Foo could not be found" dialog, such that if dependent
5015   // libraries (such as GDI+) are not preset, we gracefully fail to load those
5016   // XPCOM components, instead of being ungraceful.
5017   UINT realMode = SetErrorMode(0);
5018   realMode |= SEM_FAILCRITICALERRORS;
5019   // If XRE_NO_WINDOWS_CRASH_DIALOG is set, suppress displaying the "This
5020   // application has crashed" dialog box.  This is mainly useful for
5021   // automated testing environments, e.g. tinderbox, where there's no need
5022   // for a dozen of the dialog boxes to litter the console
5023   if (getenv("XRE_NO_WINDOWS_CRASH_DIALOG"))
5024     realMode |= SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX;
5025 
5026   SetErrorMode(realMode);
5027 
5028 #endif
5029 
5030 #if defined (DEBUG) && defined(XP_WIN)
5031   // Send MSCRT Warnings, Errors and Assertions to stderr.
5032   // See http://msdn.microsoft.com/en-us/library/1y71x448(v=VS.80).aspx
5033   // and http://msdn.microsoft.com/en-us/library/a68f826y(v=VS.80).aspx.
5034 
5035   _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
5036   _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
5037   _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
5038   _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
5039   _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
5040   _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
5041 
5042   _CrtSetReportHook(MSCRTReportHook);
5043 #endif
5044 
5045   InstallSignalHandlers(progname);
5046 
5047   // Unbuffer stdout, needed for tinderbox tests.
5048   setbuf(stdout, 0);
5049 }
5050 
5051 void
OverrideDefaultLocaleIfNeeded()5052 OverrideDefaultLocaleIfNeeded() {
5053   // Read pref to decide whether to override default locale with US English.
5054   if (mozilla::Preferences::GetBool("javascript.use_us_english_locale", false)) {
5055     // Set the application-wide C-locale. Needed to resist fingerprinting
5056     // of Date.toLocaleFormat(). We use the locale to "C.UTF-8" if possible,
5057     // to avoid interfering with non-ASCII keyboard input on some Linux desktops.
5058     // Otherwise fall back to the "C" locale, which is available on all platforms.
5059     setlocale(LC_ALL, "C.UTF-8") || setlocale(LC_ALL, "C");
5060   }
5061 }
5062 
5063 void
XRE_EnableSameExecutableForContentProc()5064 XRE_EnableSameExecutableForContentProc() {
5065   if (!PR_GetEnv("MOZ_SEPARATE_CHILD_PROCESS")) {
5066     mozilla::ipc::GeckoChildProcessHost::EnableSameExecutableForContentProc();
5067   }
5068 }
5069