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