Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
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/. */
6 #if defined(MOZ_WIDGET_QT)
7 #include <QGuiApplication>
8 #include <QStringList>
9 #include "nsQAppInstance.h"
10 #endif // MOZ_WIDGET_QT
12 #include "mozilla/dom/ContentParent.h"
13 #include "mozilla/dom/ContentChild.h"
15 #include "mozilla/ArrayUtils.h"
16 #include "mozilla/Attributes.h"
17 #include "mozilla/IOInterposer.h"
18 #include "mozilla/Likely.h"
19 #include "mozilla/Poison.h"
20 #include "mozilla/Preferences.h"
21 #include "mozilla/Telemetry.h"
23 #include "nsAppRunner.h"
24 #include "mozilla/AppData.h"
25 #include "nsUpdateDriver.h"
26 #include "ProfileReset.h"
28 #ifdef MOZ_INSTRUMENT_EVENT_LOOP
29 #include "EventTracer.h"
30 #endif
32 #ifdef XP_MACOSX
33 #include "nsVersionComparator.h"
34 #include "MacLaunchHelper.h"
35 #include "MacApplicationDelegate.h"
36 #include "MacAutoreleasePool.h"
37 // these are needed for sysctl
38 #include <sys/types.h>
39 #include <sys/sysctl.h>
40 #endif
42 #include "prmem.h"
43 #include "prnetdb.h"
44 #include "prprf.h"
45 #include "prproces.h"
46 #include "prenv.h"
48 #include "nsIAppShellService.h"
49 #include "nsIAppStartup.h"
50 #include "nsIAppStartupNotifier.h"
51 #include "nsIMutableArray.h"
52 #include "nsICategoryManager.h"
53 #include "nsIChromeRegistry.h"
54 #include "nsICommandLineRunner.h"
55 #include "nsIComponentManager.h"
56 #include "nsIComponentRegistrar.h"
57 #include "nsIContentHandler.h"
58 #include "nsIDialogParamBlock.h"
59 #include "nsIDOMWindow.h"
60 #include "mozilla/ModuleUtils.h"
61 #include "nsIIOService2.h"
62 #include "nsIObserverService.h"
63 #include "nsINativeAppSupport.h"
64 #include "nsIProcess.h"
65 #include "nsIProfileUnlocker.h"
66 #include "nsIPromptService.h"
67 #include "nsIServiceManager.h"
68 #include "nsIStringBundle.h"
69 #include "nsISupportsPrimitives.h"
70 #include "nsIToolkitChromeRegistry.h"
71 #include "nsIToolkitProfile.h"
72 #include "nsIToolkitProfileService.h"
73 #include "nsIURI.h"
74 #include "nsIWindowCreator.h"
75 #include "nsIWindowMediator.h"
76 #include "nsIWindowWatcher.h"
77 #include "nsIXULAppInfo.h"
78 #include "nsIXULRuntime.h"
79 #include "nsPIDOMWindow.h"
80 #include "nsIBaseWindow.h"
81 #include "nsIWidget.h"
82 #include "nsIDocShell.h"
83 #include "nsAppShellCID.h"
84 #include "mozilla/scache/StartupCache.h"
86 #include "mozilla/unused.h"
88 #ifdef XP_WIN
89 #include "nsIWinAppHelper.h"
90 #include <windows.h>
91 #include "cairo/cairo-features.h"
92 #include "mozilla/WindowsVersion.h"
93 #ifdef MOZ_METRO
94 #include <roapi.h>
95 #endif
97 #ifndef PROCESS_DEP_ENABLE
98 #define PROCESS_DEP_ENABLE 0x1
99 #endif
100 #endif
102 #include "nsCRT.h"
103 #include "nsCOMPtr.h"
104 #include "nsDirectoryServiceDefs.h"
105 #include "nsDirectoryServiceUtils.h"
106 #include "nsEmbedCID.h"
107 #include "nsNetUtil.h"
108 #include "nsReadableUtils.h"
109 #include "nsXPCOM.h"
110 #include "nsXPCOMCIDInternal.h"
111 #include "nsXPIDLString.h"
112 #include "nsPrintfCString.h"
113 #include "nsVersionComparator.h"
115 #include "nsAppDirectoryServiceDefs.h"
116 #include "nsXULAppAPI.h"
117 #include "nsXREDirProvider.h"
118 #include "nsToolkitCompsCID.h"
120 #if defined(XP_WIN) && defined(MOZ_METRO)
121 #include "updatehelper.h"
122 #endif
124 #include "nsINIParser.h"
125 #include "mozilla/Omnijar.h"
126 #include "mozilla/StartupTimeline.h"
127 #include "mozilla/LateWriteChecks.h"
129 #include <stdlib.h>
131 #ifdef XP_UNIX
132 #include <sys/stat.h>
133 #include <unistd.h>
134 #include <pwd.h>
135 #endif
137 #ifdef XP_WIN
138 #include <process.h>
139 #include <shlobj.h>
140 #include "nsThreadUtils.h"
141 #include <comdef.h>
142 #include <wbemidl.h>
143 #endif
145 #ifdef XP_MACOSX
146 #include "nsILocalFileMac.h"
147 #include "nsCommandLineServiceMac.h"
148 #endif
150 // for X remote support
151 #ifdef MOZ_ENABLE_XREMOTE
152 #include "XRemoteClient.h"
153 #include "nsIRemoteService.h"
154 #endif
156 #ifdef NS_TRACE_MALLOC
157 #include "nsTraceMalloc.h"
158 #endif
160 #if defined(DEBUG) && defined(XP_WIN32)
161 #include <malloc.h>
162 #endif
164 #if defined (XP_MACOSX)
165 #include <Carbon/Carbon.h>
166 #endif
168 #ifdef DEBUG
169 #include "prlog.h"
170 #endif
172 #ifdef MOZ_JPROF
173 #include "jprof.h"
174 #endif
176 #ifdef MOZ_CRASHREPORTER
177 #include "nsExceptionHandler.h"
178 #include "nsICrashReporter.h"
179 #define NS_CRASHREPORTER_CONTRACTID "@mozilla.org/toolkit/crash-reporter;1"
180 #include "nsIPrefService.h"
181 #endif
183 #include "base/command_line.h"
184 #ifdef MOZ_ENABLE_TESTS
185 #include "GTestRunner.h"
186 #endif
188 #ifdef MOZ_WIDGET_ANDROID
189 #include "AndroidBridge.h"
190 #endif
192 extern uint32_t gRestartMode;
193 extern void InstallSignalHandlers(const char *ProgramName);
194 #include "nsX11ErrorHandler.h"
196 #define FILE_COMPATIBILITY_INFO NS_LITERAL_CSTRING("compatibility.ini")
197 #define FILE_INVALIDATE_CACHES NS_LITERAL_CSTRING(".purgecaches")
199 int gArgc;
200 char **gArgv;
202 static const char gToolkitVersion[] = NS_STRINGIFY(GRE_MILESTONE);
203 static const char gToolkitBuildID[] = NS_STRINGIFY(GRE_BUILDID);
205 static nsIProfileLock* gProfileLock;
207 int gRestartArgc;
208 char **gRestartArgv;
210 #ifdef MOZ_WIDGET_QT
211 static int gQtOnlyArgc;
212 static char **gQtOnlyArgv;
213 #endif
215 #if defined(MOZ_WIDGET_GTK)
216 #if defined(DEBUG) || defined(NS_BUILD_REFCNT_LOGGING) \
217 || defined(NS_TRACE_MALLOC)
218 #define CLEANUP_MEMORY 1
219 #define PANGO_ENABLE_BACKEND
220 #include <pango/pangofc-fontmap.h>
221 #endif
222 #include <gtk/gtk.h>
223 #ifdef MOZ_X11
224 #include <gdk/gdkx.h>
225 #endif /* MOZ_X11 */
226 #include "nsGTKToolkit.h"
227 #include <fontconfig/fontconfig.h>
228 #endif
229 #include "BinaryPath.h"
231 #ifdef MOZ_LINKER
232 extern "C" MFBT_API bool IsSignalHandlingBroken();
233 #endif
235 namespace mozilla {
236 int (*RunGTest)() = 0;
237 }
239 using namespace mozilla;
240 using mozilla::unused;
241 using mozilla::scache::StartupCache;
242 using mozilla::dom::ContentParent;
243 using mozilla::dom::ContentChild;
245 // Save literal putenv string to environment variable.
246 static void
247 SaveToEnv(const char *putenv)
248 {
249 char *expr = strdup(putenv);
250 if (expr)
251 PR_SetEnv(expr);
252 // We intentionally leak |expr| here since it is required by PR_SetEnv.
253 }
255 // Tests that an environment variable exists and has a value
256 static bool
257 EnvHasValue(const char *name)
258 {
259 const char *val = PR_GetEnv(name);
260 return (val && *val);
261 }
263 // Save the given word to the specified environment variable.
264 static void
265 SaveWordToEnv(const char *name, const nsACString & word)
266 {
267 char *expr = PR_smprintf("%s=%s", name, PromiseFlatCString(word).get());
268 if (expr)
269 PR_SetEnv(expr);
270 // We intentionally leak |expr| here since it is required by PR_SetEnv.
271 }
273 // Save the path of the given file to the specified environment variable.
274 static void
275 SaveFileToEnv(const char *name, nsIFile *file)
276 {
277 #ifdef XP_WIN
278 nsAutoString path;
279 file->GetPath(path);
280 SetEnvironmentVariableW(NS_ConvertASCIItoUTF16(name).get(), path.get());
281 #else
282 nsAutoCString path;
283 file->GetNativePath(path);
284 SaveWordToEnv(name, path);
285 #endif
286 }
288 // Load the path of a file saved with SaveFileToEnv
289 static already_AddRefed<nsIFile>
290 GetFileFromEnv(const char *name)
291 {
292 nsresult rv;
293 nsCOMPtr<nsIFile> file;
295 #ifdef XP_WIN
296 WCHAR path[_MAX_PATH];
297 if (!GetEnvironmentVariableW(NS_ConvertASCIItoUTF16(name).get(),
298 path, _MAX_PATH))
299 return nullptr;
301 rv = NS_NewLocalFile(nsDependentString(path), true, getter_AddRefs(file));
302 if (NS_FAILED(rv))
303 return nullptr;
305 return file.forget();
306 #else
307 const char *arg = PR_GetEnv(name);
308 if (!arg || !*arg)
309 return nullptr;
311 rv = NS_NewNativeLocalFile(nsDependentCString(arg), true,
312 getter_AddRefs(file));
313 if (NS_FAILED(rv))
314 return nullptr;
316 return file.forget();
317 #endif
318 }
320 // Save the path of the given word to the specified environment variable
321 // provided the environment variable does not have a value.
322 static void
323 SaveWordToEnvIfUnset(const char *name, const nsACString & word)
324 {
325 if (!EnvHasValue(name))
326 SaveWordToEnv(name, word);
327 }
329 // Save the path of the given file to the specified environment variable
330 // provided the environment variable does not have a value.
331 static void
332 SaveFileToEnvIfUnset(const char *name, nsIFile *file)
333 {
334 if (!EnvHasValue(name))
335 SaveFileToEnv(name, file);
336 }
338 static bool
339 strimatch(const char* lowerstr, const char* mixedstr)
340 {
341 while(*lowerstr) {
342 if (!*mixedstr) return false; // mixedstr is shorter
343 if (tolower(*mixedstr) != *lowerstr) return false; // no match
345 ++lowerstr;
346 ++mixedstr;
347 }
349 if (*mixedstr) return false; // lowerstr is shorter
351 return true;
352 }
354 /**
355 * Output a string to the user. This method is really only meant to be used to
356 * output last-ditch error messages designed for developers NOT END USERS.
357 *
358 * @param isError
359 * Pass true to indicate severe errors.
360 * @param fmt
361 * printf-style format string followed by arguments.
362 */
363 static void Output(bool isError, const char *fmt, ... )
364 {
365 va_list ap;
366 va_start(ap, fmt);
368 #if defined(XP_WIN) && !MOZ_WINCONSOLE
369 char *msg = PR_vsmprintf(fmt, ap);
370 if (msg)
371 {
372 UINT flags = MB_OK;
373 if (isError)
374 flags |= MB_ICONERROR;
375 else
376 flags |= MB_ICONINFORMATION;
378 wchar_t wide_msg[1024];
379 MultiByteToWideChar(CP_ACP,
380 0,
381 msg,
382 -1,
383 wide_msg,
384 sizeof(wide_msg) / sizeof(wchar_t));
386 MessageBoxW(nullptr, wide_msg, L"XULRunner", flags);
387 PR_smprintf_free(msg);
388 }
389 #else
390 vfprintf(stderr, fmt, ap);
391 #endif
393 va_end(ap);
394 }
396 enum RemoteResult {
397 REMOTE_NOT_FOUND = 0,
398 REMOTE_FOUND = 1,
399 REMOTE_ARG_BAD = 2
400 };
402 enum ArgResult {
403 ARG_NONE = 0,
404 ARG_FOUND = 1,
405 ARG_BAD = 2 // you wanted a param, but there isn't one
406 };
408 static void RemoveArg(char **argv)
409 {
410 do {
411 *argv = *(argv + 1);
412 ++argv;
413 } while (*argv);
415 --gArgc;
416 }
418 /**
419 * Check for a commandline flag. If the flag takes a parameter, the
420 * parameter is returned in aParam. Flags may be in the form -arg or
421 * --arg (or /arg on win32).
422 *
423 * @param aArg the parameter to check. Must be lowercase.
424 * @param aCheckOSInt if true returns ARG_BAD if the osint argument is present
425 * when aArg is also present.
426 * @param aParam if non-null, the -arg <data> will be stored in this pointer.
427 * This is *not* allocated, but rather a pointer to the argv data.
428 * @param aRemArg if true, the argument is removed from the gArgv array.
429 */
430 static ArgResult
431 CheckArg(const char* aArg, bool aCheckOSInt = false, const char **aParam = nullptr, bool aRemArg = true)
432 {
433 NS_ABORT_IF_FALSE(gArgv, "gArgv must be initialized before CheckArg()");
435 char **curarg = gArgv + 1; // skip argv[0]
436 ArgResult ar = ARG_NONE;
438 while (*curarg) {
439 char *arg = curarg[0];
441 if (arg[0] == '-'
442 #if defined(XP_WIN)
443 || *arg == '/'
444 #endif
445 ) {
446 ++arg;
447 if (*arg == '-')
448 ++arg;
450 if (strimatch(aArg, arg)) {
451 if (aRemArg)
452 RemoveArg(curarg);
453 if (!aParam) {
454 ar = ARG_FOUND;
455 break;
456 }
458 if (*curarg) {
459 if (**curarg == '-'
460 #if defined(XP_WIN)
461 || **curarg == '/'
462 #endif
463 )
464 return ARG_BAD;
466 *aParam = *curarg;
467 if (aRemArg)
468 RemoveArg(curarg);
469 ar = ARG_FOUND;
470 break;
471 }
472 return ARG_BAD;
473 }
474 }
476 ++curarg;
477 }
479 if (aCheckOSInt && ar == ARG_FOUND) {
480 ArgResult arOSInt = CheckArg("osint");
481 if (arOSInt == ARG_FOUND) {
482 ar = ARG_BAD;
483 PR_fprintf(PR_STDERR, "Error: argument -osint is invalid\n");
484 }
485 }
487 return ar;
488 }
490 #if defined(XP_WIN)
491 /**
492 * Check for a commandline flag from the windows shell and remove it from the
493 * argv used when restarting. Flags MUST be in the form -arg.
494 *
495 * @param aArg the parameter to check. Must be lowercase.
496 */
497 static ArgResult
498 CheckArgShell(const char* aArg)
499 {
500 char **curarg = gRestartArgv + 1; // skip argv[0]
502 while (*curarg) {
503 char *arg = curarg[0];
505 if (arg[0] == '-') {
506 ++arg;
508 if (strimatch(aArg, arg)) {
509 do {
510 *curarg = *(curarg + 1);
511 ++curarg;
512 } while (*curarg);
514 --gRestartArgc;
516 return ARG_FOUND;
517 }
518 }
520 ++curarg;
521 }
523 return ARG_NONE;
524 }
526 /**
527 * Enabled Native App Support to process DDE messages when the app needs to
528 * restart and the app has been launched by the Windows shell to open an url.
529 * When aWait is false this will process the DDE events manually. This prevents
530 * Windows from displaying an error message due to the DDE message not being
531 * acknowledged.
532 */
533 static void
534 ProcessDDE(nsINativeAppSupport* aNative, bool aWait)
535 {
536 // When the app is launched by the windows shell the windows shell
537 // expects the app to be available for DDE messages and if it isn't
538 // windows displays an error dialog. To prevent the error the DDE server
539 // is enabled and pending events are processed when the app needs to
540 // restart after it was launched by the shell with the requestpending
541 // argument. The requestpending pending argument is removed to
542 // differentiate it from being launched when an app restart is not
543 // required.
544 ArgResult ar;
545 ar = CheckArgShell("requestpending");
546 if (ar == ARG_FOUND) {
547 aNative->Enable(); // enable win32 DDE responses
548 if (aWait) {
549 nsIThread *thread = NS_GetCurrentThread();
550 // This is just a guesstimate based on testing different values.
551 // If count is 8 or less windows will display an error dialog.
552 int32_t count = 20;
553 while(--count >= 0) {
554 NS_ProcessNextEvent(thread);
555 PR_Sleep(PR_MillisecondsToInterval(1));
556 }
557 }
558 }
559 }
560 #endif
562 /**
563 * Determines if there is support for showing the profile manager
564 *
565 * @return true in all environments except for Windows Metro
566 */
567 static bool
568 CanShowProfileManager()
569 {
570 #if defined(XP_WIN)
571 return XRE_GetWindowsEnvironment() == WindowsEnvironmentType_Desktop;
572 #else
573 return true;
574 #endif
575 }
578 bool gSafeMode = false;
580 /**
581 * The nsXULAppInfo object implements nsIFactory so that it can be its own
582 * singleton.
583 */
584 class nsXULAppInfo : public nsIXULAppInfo,
585 #ifdef XP_WIN
586 public nsIWinAppHelper,
587 #endif
588 #ifdef MOZ_CRASHREPORTER
589 public nsICrashReporter,
590 #endif
591 public nsIXULRuntime
593 {
594 public:
595 MOZ_CONSTEXPR nsXULAppInfo() {}
596 NS_DECL_ISUPPORTS_INHERITED
597 NS_DECL_NSIXULAPPINFO
598 NS_DECL_NSIXULRUNTIME
599 #ifdef MOZ_CRASHREPORTER
600 NS_DECL_NSICRASHREPORTER
601 #endif
602 #ifdef XP_WIN
603 NS_DECL_NSIWINAPPHELPER
604 #endif
605 };
607 NS_INTERFACE_MAP_BEGIN(nsXULAppInfo)
608 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXULRuntime)
609 NS_INTERFACE_MAP_ENTRY(nsIXULRuntime)
610 #ifdef XP_WIN
611 NS_INTERFACE_MAP_ENTRY(nsIWinAppHelper)
612 #endif
613 #ifdef MOZ_CRASHREPORTER
614 NS_INTERFACE_MAP_ENTRY(nsICrashReporter)
615 #endif
616 NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIXULAppInfo, gAppData ||
617 XRE_GetProcessType() == GeckoProcessType_Content)
618 NS_INTERFACE_MAP_END
620 NS_IMETHODIMP_(MozExternalRefCountType)
621 nsXULAppInfo::AddRef()
622 {
623 return 1;
624 }
626 NS_IMETHODIMP_(MozExternalRefCountType)
627 nsXULAppInfo::Release()
628 {
629 return 1;
630 }
632 NS_IMETHODIMP
633 nsXULAppInfo::GetVendor(nsACString& aResult)
634 {
635 if (XRE_GetProcessType() == GeckoProcessType_Content) {
636 return NS_ERROR_NOT_AVAILABLE;
637 }
638 aResult.Assign(gAppData->vendor);
640 return NS_OK;
641 }
643 NS_IMETHODIMP
644 nsXULAppInfo::GetName(nsACString& aResult)
645 {
646 if (XRE_GetProcessType() == GeckoProcessType_Content) {
647 ContentChild* cc = ContentChild::GetSingleton();
648 aResult = cc->GetAppInfo().name;
649 return NS_OK;
650 }
651 aResult.Assign(gAppData->name);
653 return NS_OK;
654 }
656 NS_IMETHODIMP
657 nsXULAppInfo::GetID(nsACString& aResult)
658 {
659 if (XRE_GetProcessType() == GeckoProcessType_Content) {
660 return NS_ERROR_NOT_AVAILABLE;
661 }
662 aResult.Assign(gAppData->ID);
664 return NS_OK;
665 }
667 NS_IMETHODIMP
668 nsXULAppInfo::GetVersion(nsACString& aResult)
669 {
670 if (XRE_GetProcessType() == GeckoProcessType_Content) {
671 ContentChild* cc = ContentChild::GetSingleton();
672 aResult = cc->GetAppInfo().version;
673 return NS_OK;
674 }
675 aResult.Assign(gAppData->version);
677 return NS_OK;
678 }
680 NS_IMETHODIMP
681 nsXULAppInfo::GetPlatformVersion(nsACString& aResult)
682 {
683 aResult.Assign(gToolkitVersion);
685 return NS_OK;
686 }
688 NS_IMETHODIMP
689 nsXULAppInfo::GetAppBuildID(nsACString& aResult)
690 {
691 if (XRE_GetProcessType() == GeckoProcessType_Content) {
692 ContentChild* cc = ContentChild::GetSingleton();
693 aResult = cc->GetAppInfo().buildID;
694 return NS_OK;
695 }
696 aResult.Assign(gAppData->buildID);
698 return NS_OK;
699 }
701 NS_IMETHODIMP
702 nsXULAppInfo::GetPlatformBuildID(nsACString& aResult)
703 {
704 aResult.Assign(gToolkitBuildID);
706 return NS_OK;
707 }
709 NS_IMETHODIMP
710 nsXULAppInfo::GetUAName(nsACString& aResult)
711 {
712 if (XRE_GetProcessType() == GeckoProcessType_Content) {
713 ContentChild* cc = ContentChild::GetSingleton();
714 aResult = cc->GetAppInfo().UAName;
715 return NS_OK;
716 }
717 aResult.Assign(gAppData->UAName);
719 return NS_OK;
720 }
722 NS_IMETHODIMP
723 nsXULAppInfo::GetLogConsoleErrors(bool *aResult)
724 {
725 *aResult = gLogConsoleErrors;
726 return NS_OK;
727 }
729 NS_IMETHODIMP
730 nsXULAppInfo::SetLogConsoleErrors(bool aValue)
731 {
732 gLogConsoleErrors = aValue;
733 return NS_OK;
734 }
736 NS_IMETHODIMP
737 nsXULAppInfo::GetInSafeMode(bool *aResult)
738 {
739 *aResult = gSafeMode;
740 return NS_OK;
741 }
743 NS_IMETHODIMP
744 nsXULAppInfo::GetOS(nsACString& aResult)
745 {
746 aResult.AssignLiteral(OS_TARGET);
747 return NS_OK;
748 }
750 NS_IMETHODIMP
751 nsXULAppInfo::GetXPCOMABI(nsACString& aResult)
752 {
753 #ifdef TARGET_XPCOM_ABI
754 aResult.AssignLiteral(TARGET_XPCOM_ABI);
755 return NS_OK;
756 #else
757 return NS_ERROR_NOT_AVAILABLE;
758 #endif
759 }
761 NS_IMETHODIMP
762 nsXULAppInfo::GetWidgetToolkit(nsACString& aResult)
763 {
764 aResult.AssignLiteral(MOZ_WIDGET_TOOLKIT);
765 return NS_OK;
766 }
768 // Ensure that the GeckoProcessType enum, defined in xpcom/build/nsXULAppAPI.h,
769 // is synchronized with the const unsigned longs defined in
770 // xpcom/system/nsIXULRuntime.idl.
771 #define SYNC_ENUMS(a,b) \
772 static_assert(nsIXULRuntime::PROCESS_TYPE_ ## a == \
773 static_cast<int>(GeckoProcessType_ ## b), \
774 "GeckoProcessType in nsXULAppAPI.h not synchronized with nsIXULRuntime.idl");
776 SYNC_ENUMS(DEFAULT, Default)
777 SYNC_ENUMS(PLUGIN, Plugin)
778 SYNC_ENUMS(CONTENT, Content)
779 SYNC_ENUMS(IPDLUNITTEST, IPDLUnitTest)
781 // .. and ensure that that is all of them:
782 static_assert(GeckoProcessType_IPDLUnitTest + 1 == GeckoProcessType_End,
783 "Did not find the final GeckoProcessType");
785 NS_IMETHODIMP
786 nsXULAppInfo::GetProcessType(uint32_t* aResult)
787 {
788 NS_ENSURE_ARG_POINTER(aResult);
789 *aResult = XRE_GetProcessType();
790 return NS_OK;
791 }
793 NS_IMETHODIMP
794 nsXULAppInfo::GetProcessID(uint32_t* aResult)
795 {
796 #ifdef XP_WIN
797 *aResult = GetCurrentProcessId();
798 #else
799 *aResult = getpid();
800 #endif
801 return NS_OK;
802 }
804 static bool gBrowserTabsRemote = false;
805 static bool gBrowserTabsRemoteInitialized = false;
807 NS_IMETHODIMP
808 nsXULAppInfo::GetBrowserTabsRemote(bool* aResult)
809 {
810 *aResult = BrowserTabsRemote();
811 return NS_OK;
812 }
814 NS_IMETHODIMP
815 nsXULAppInfo::EnsureContentProcess()
816 {
817 if (XRE_GetProcessType() != GeckoProcessType_Default)
818 return NS_ERROR_NOT_AVAILABLE;
820 nsRefPtr<ContentParent> unused = ContentParent::GetNewOrUsed();
821 return NS_OK;
822 }
824 NS_IMETHODIMP
825 nsXULAppInfo::InvalidateCachesOnRestart()
826 {
827 nsCOMPtr<nsIFile> file;
828 nsresult rv = NS_GetSpecialDirectory(NS_APP_PROFILE_DIR_STARTUP,
829 getter_AddRefs(file));
830 if (NS_FAILED(rv))
831 return rv;
832 if (!file)
833 return NS_ERROR_NOT_AVAILABLE;
835 file->AppendNative(FILE_COMPATIBILITY_INFO);
837 nsINIParser parser;
838 rv = parser.Init(file);
839 if (NS_FAILED(rv)) {
840 // This fails if compatibility.ini is not there, so we'll
841 // flush the caches on the next restart anyways.
842 return NS_OK;
843 }
845 nsAutoCString buf;
846 rv = parser.GetString("Compatibility", "InvalidateCaches", buf);
848 if (NS_FAILED(rv)) {
849 PRFileDesc *fd = nullptr;
850 file->OpenNSPRFileDesc(PR_RDWR | PR_APPEND, 0600, &fd);
851 if (!fd) {
852 NS_ERROR("could not create output stream");
853 return NS_ERROR_NOT_AVAILABLE;
854 }
855 static const char kInvalidationHeader[] = NS_LINEBREAK "InvalidateCaches=1" NS_LINEBREAK;
856 PR_Write(fd, kInvalidationHeader, sizeof(kInvalidationHeader) - 1);
857 PR_Close(fd);
858 }
859 return NS_OK;
860 }
862 NS_IMETHODIMP
863 nsXULAppInfo::GetReplacedLockTime(PRTime *aReplacedLockTime)
864 {
865 if (!gProfileLock)
866 return NS_ERROR_NOT_AVAILABLE;
867 gProfileLock->GetReplacedLockTime(aReplacedLockTime);
868 return NS_OK;
869 }
871 NS_IMETHODIMP
872 nsXULAppInfo::GetLastRunCrashID(nsAString &aLastRunCrashID)
873 {
874 #ifdef MOZ_CRASHREPORTER
875 CrashReporter::GetLastRunCrashID(aLastRunCrashID);
876 return NS_OK;
877 #else
878 return NS_ERROR_NOT_IMPLEMENTED;
879 #endif
880 }
882 NS_IMETHODIMP
883 nsXULAppInfo::GetIsReleaseBuild(bool* aResult)
884 {
885 #ifdef RELEASE_BUILD
886 *aResult = true;
887 #else
888 *aResult = false;
889 #endif
890 return NS_OK;
891 }
893 NS_IMETHODIMP
894 nsXULAppInfo::GetIsOfficialBranding(bool* aResult)
895 {
896 #ifdef MOZ_OFFICIAL_BRANDING
897 *aResult = true;
898 #else
899 *aResult = false;
900 #endif
901 return NS_OK;
902 }
904 NS_IMETHODIMP
905 nsXULAppInfo::GetDefaultUpdateChannel(nsACString& aResult)
906 {
907 aResult.AssignLiteral(NS_STRINGIFY(MOZ_UPDATE_CHANNEL));
908 return NS_OK;
909 }
911 NS_IMETHODIMP
912 nsXULAppInfo::GetDistributionID(nsACString& aResult)
913 {
914 aResult.AssignLiteral(MOZ_DISTRIBUTION_ID);
915 return NS_OK;
916 }
918 #ifdef XP_WIN
919 // Matches the enum in WinNT.h for the Vista SDK but renamed so that we can
920 // safely build with the Vista SDK and without it.
921 typedef enum
922 {
923 VistaTokenElevationTypeDefault = 1,
924 VistaTokenElevationTypeFull,
925 VistaTokenElevationTypeLimited
926 } VISTA_TOKEN_ELEVATION_TYPE;
928 // avoid collision with TokeElevationType enum in WinNT.h
929 // of the Vista SDK
930 #define VistaTokenElevationType static_cast< TOKEN_INFORMATION_CLASS >( 18 )
932 NS_IMETHODIMP
933 nsXULAppInfo::GetUserCanElevate(bool *aUserCanElevate)
934 {
935 HANDLE hToken;
937 VISTA_TOKEN_ELEVATION_TYPE elevationType;
938 DWORD dwSize;
940 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken) ||
941 !GetTokenInformation(hToken, VistaTokenElevationType, &elevationType,
942 sizeof(elevationType), &dwSize)) {
943 *aUserCanElevate = false;
944 }
945 else {
946 // The possible values returned for elevationType and their meanings are:
947 // TokenElevationTypeDefault: The token does not have a linked token
948 // (e.g. UAC disabled or a standard user, so they can't be elevated)
949 // TokenElevationTypeFull: The token is linked to an elevated token
950 // (e.g. UAC is enabled and the user is already elevated so they can't
951 // be elevated again)
952 // TokenElevationTypeLimited: The token is linked to a limited token
953 // (e.g. UAC is enabled and the user is not elevated, so they can be
954 // elevated)
955 *aUserCanElevate = (elevationType == VistaTokenElevationTypeLimited);
956 }
958 if (hToken)
959 CloseHandle(hToken);
961 return NS_OK;
962 }
963 #endif
965 #ifdef MOZ_CRASHREPORTER
966 NS_IMETHODIMP
967 nsXULAppInfo::GetEnabled(bool *aEnabled)
968 {
969 *aEnabled = CrashReporter::GetEnabled();
970 return NS_OK;
971 }
973 NS_IMETHODIMP
974 nsXULAppInfo::SetEnabled(bool aEnabled)
975 {
976 if (aEnabled) {
977 if (CrashReporter::GetEnabled())
978 // no point in erroring for double-enabling
979 return NS_OK;
981 nsCOMPtr<nsIFile> xreDirectory;
982 if (gAppData) {
983 xreDirectory = gAppData->xreDirectory;
984 }
985 else {
986 // We didn't get started through XRE_Main, probably
987 nsCOMPtr<nsIFile> greDir;
988 NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(greDir));
989 if (!greDir)
990 return NS_ERROR_FAILURE;
992 xreDirectory = do_QueryInterface(greDir);
993 if (!xreDirectory)
994 return NS_ERROR_FAILURE;
995 }
996 return CrashReporter::SetExceptionHandler(xreDirectory, true);
997 }
998 else {
999 if (!CrashReporter::GetEnabled())
1000 // no point in erroring for double-disabling
1001 return NS_OK;
1003 return CrashReporter::UnsetExceptionHandler();
1004 }
1005 }
1007 NS_IMETHODIMP
1008 nsXULAppInfo::GetServerURL(nsIURL** aServerURL)
1009 {
1010 if (!CrashReporter::GetEnabled())
1011 return NS_ERROR_NOT_INITIALIZED;
1013 nsAutoCString data;
1014 if (!CrashReporter::GetServerURL(data)) {
1015 return NS_ERROR_FAILURE;
1016 }
1017 nsCOMPtr<nsIURI> uri;
1018 NS_NewURI(getter_AddRefs(uri), data);
1019 if (!uri)
1020 return NS_ERROR_FAILURE;
1022 nsCOMPtr<nsIURL> url;
1023 url = do_QueryInterface(uri);
1024 NS_ADDREF(*aServerURL = url);
1026 return NS_OK;
1027 }
1029 NS_IMETHODIMP
1030 nsXULAppInfo::SetServerURL(nsIURL* aServerURL)
1031 {
1032 bool schemeOk;
1033 // only allow https or http URLs
1034 nsresult rv = aServerURL->SchemeIs("https", &schemeOk);
1035 NS_ENSURE_SUCCESS(rv, rv);
1036 if (!schemeOk) {
1037 rv = aServerURL->SchemeIs("http", &schemeOk);
1038 NS_ENSURE_SUCCESS(rv, rv);
1040 if (!schemeOk)
1041 return NS_ERROR_INVALID_ARG;
1042 }
1043 nsAutoCString spec;
1044 rv = aServerURL->GetSpec(spec);
1045 NS_ENSURE_SUCCESS(rv, rv);
1047 return CrashReporter::SetServerURL(spec);
1048 }
1050 NS_IMETHODIMP
1051 nsXULAppInfo::GetMinidumpPath(nsIFile** aMinidumpPath)
1052 {
1053 if (!CrashReporter::GetEnabled())
1054 return NS_ERROR_NOT_INITIALIZED;
1056 nsAutoString path;
1057 if (!CrashReporter::GetMinidumpPath(path))
1058 return NS_ERROR_FAILURE;
1060 nsresult rv = NS_NewLocalFile(path, false, aMinidumpPath);
1061 NS_ENSURE_SUCCESS(rv, rv);
1062 return NS_OK;
1063 }
1065 NS_IMETHODIMP
1066 nsXULAppInfo::SetMinidumpPath(nsIFile* aMinidumpPath)
1067 {
1068 nsAutoString path;
1069 nsresult rv = aMinidumpPath->GetPath(path);
1070 NS_ENSURE_SUCCESS(rv, rv);
1071 return CrashReporter::SetMinidumpPath(path);
1072 }
1074 NS_IMETHODIMP
1075 nsXULAppInfo::AnnotateCrashReport(const nsACString& key,
1076 const nsACString& data)
1077 {
1078 return CrashReporter::AnnotateCrashReport(key, data);
1079 }
1081 NS_IMETHODIMP
1082 nsXULAppInfo::AppendAppNotesToCrashReport(const nsACString& data)
1083 {
1084 return CrashReporter::AppendAppNotesToCrashReport(data);
1085 }
1087 NS_IMETHODIMP
1088 nsXULAppInfo::RegisterAppMemory(uint64_t pointer,
1089 uint64_t len)
1090 {
1091 return CrashReporter::RegisterAppMemory((void *)pointer, len);
1092 }
1094 NS_IMETHODIMP
1095 nsXULAppInfo::WriteMinidumpForException(void* aExceptionInfo)
1096 {
1097 #ifdef XP_WIN32
1098 return CrashReporter::WriteMinidumpForException(static_cast<EXCEPTION_POINTERS*>(aExceptionInfo));
1099 #else
1100 return NS_ERROR_NOT_IMPLEMENTED;
1101 #endif
1102 }
1104 NS_IMETHODIMP
1105 nsXULAppInfo::AppendObjCExceptionInfoToAppNotes(void* aException)
1106 {
1107 #ifdef XP_MACOSX
1108 return CrashReporter::AppendObjCExceptionInfoToAppNotes(aException);
1109 #else
1110 return NS_ERROR_NOT_IMPLEMENTED;
1111 #endif
1112 }
1114 NS_IMETHODIMP
1115 nsXULAppInfo::GetSubmitReports(bool* aEnabled)
1116 {
1117 return CrashReporter::GetSubmitReports(aEnabled);
1118 }
1120 NS_IMETHODIMP
1121 nsXULAppInfo::SetSubmitReports(bool aEnabled)
1122 {
1123 return CrashReporter::SetSubmitReports(aEnabled);
1124 }
1126 NS_IMETHODIMP
1127 nsXULAppInfo::UpdateCrashEventsDir()
1128 {
1129 CrashReporter::UpdateCrashEventsDir();
1130 return NS_OK;
1131 }
1133 #endif
1135 static const nsXULAppInfo kAppInfo;
1136 static nsresult AppInfoConstructor(nsISupports* aOuter,
1137 REFNSIID aIID, void **aResult)
1138 {
1139 NS_ENSURE_NO_AGGREGATION(aOuter);
1141 return const_cast<nsXULAppInfo*>(&kAppInfo)->
1142 QueryInterface(aIID, aResult);
1143 }
1145 bool gLogConsoleErrors = false;
1147 #define NS_ENSURE_TRUE_LOG(x, ret) \
1148 PR_BEGIN_MACRO \
1149 if (MOZ_UNLIKELY(!(x))) { \
1150 NS_WARNING("NS_ENSURE_TRUE(" #x ") failed"); \
1151 gLogConsoleErrors = true; \
1152 return ret; \
1153 } \
1154 PR_END_MACRO
1156 #define NS_ENSURE_SUCCESS_LOG(res, ret) \
1157 NS_ENSURE_TRUE_LOG(NS_SUCCEEDED(res), ret)
1159 /**
1160 * Because we're starting/stopping XPCOM several times in different scenarios,
1161 * this class is a stack-based critter that makes sure that XPCOM is shut down
1162 * during early returns.
1163 */
1165 class ScopedXPCOMStartup
1166 {
1167 public:
1168 ScopedXPCOMStartup() :
1169 mServiceManager(nullptr) { }
1170 ~ScopedXPCOMStartup();
1172 nsresult Initialize();
1173 nsresult SetWindowCreator(nsINativeAppSupport* native);
1175 static nsresult CreateAppSupport(nsISupports* aOuter, REFNSIID aIID, void** aResult);
1177 private:
1178 nsIServiceManager* mServiceManager;
1179 static nsINativeAppSupport* gNativeAppSupport;
1180 };
1182 ScopedXPCOMStartup::~ScopedXPCOMStartup()
1183 {
1184 NS_IF_RELEASE(gNativeAppSupport);
1186 if (mServiceManager) {
1187 #ifdef XP_MACOSX
1188 // On OS X, we need a pool to catch cocoa objects that are autoreleased
1189 // during teardown.
1190 mozilla::MacAutoreleasePool pool;
1191 #endif
1193 nsCOMPtr<nsIAppStartup> appStartup (do_GetService(NS_APPSTARTUP_CONTRACTID));
1194 if (appStartup)
1195 appStartup->DestroyHiddenWindow();
1197 gDirServiceProvider->DoShutdown();
1198 PROFILER_MARKER("Shutdown early");
1200 WriteConsoleLog();
1202 NS_ShutdownXPCOM(mServiceManager);
1203 mServiceManager = nullptr;
1204 }
1205 }
1207 // {95d89e3e-a169-41a3-8e56-719978e15b12}
1208 #define APPINFO_CID \
1209 { 0x95d89e3e, 0xa169, 0x41a3, { 0x8e, 0x56, 0x71, 0x99, 0x78, 0xe1, 0x5b, 0x12 } }
1211 // {0C4A446C-EE82-41f2-8D04-D366D2C7A7D4}
1212 static const nsCID kNativeAppSupportCID =
1213 { 0xc4a446c, 0xee82, 0x41f2, { 0x8d, 0x4, 0xd3, 0x66, 0xd2, 0xc7, 0xa7, 0xd4 } };
1215 // {5F5E59CE-27BC-47eb-9D1F-B09CA9049836}
1216 static const nsCID kProfileServiceCID =
1217 { 0x5f5e59ce, 0x27bc, 0x47eb, { 0x9d, 0x1f, 0xb0, 0x9c, 0xa9, 0x4, 0x98, 0x36 } };
1219 static already_AddRefed<nsIFactory>
1220 ProfileServiceFactoryConstructor(const mozilla::Module& module, const mozilla::Module::CIDEntry& entry)
1221 {
1222 nsCOMPtr<nsIFactory> factory;
1223 NS_NewToolkitProfileFactory(getter_AddRefs(factory));
1224 return factory.forget();
1225 }
1227 NS_DEFINE_NAMED_CID(APPINFO_CID);
1229 static const mozilla::Module::CIDEntry kXRECIDs[] = {
1230 { &kAPPINFO_CID, false, nullptr, AppInfoConstructor },
1231 { &kProfileServiceCID, false, ProfileServiceFactoryConstructor, nullptr },
1232 { &kNativeAppSupportCID, false, nullptr, ScopedXPCOMStartup::CreateAppSupport },
1233 { nullptr }
1234 };
1236 static const mozilla::Module::ContractIDEntry kXREContracts[] = {
1237 { XULAPPINFO_SERVICE_CONTRACTID, &kAPPINFO_CID },
1238 { XULRUNTIME_SERVICE_CONTRACTID, &kAPPINFO_CID },
1239 #ifdef MOZ_CRASHREPORTER
1240 { NS_CRASHREPORTER_CONTRACTID, &kAPPINFO_CID },
1241 #endif
1242 { NS_PROFILESERVICE_CONTRACTID, &kProfileServiceCID },
1243 { NS_NATIVEAPPSUPPORT_CONTRACTID, &kNativeAppSupportCID },
1244 { nullptr }
1245 };
1247 static const mozilla::Module kXREModule = {
1248 mozilla::Module::kVersion,
1249 kXRECIDs,
1250 kXREContracts
1251 };
1253 NSMODULE_DEFN(Apprunner) = &kXREModule;
1255 nsresult
1256 ScopedXPCOMStartup::Initialize()
1257 {
1258 NS_ASSERTION(gDirServiceProvider, "Should not get here!");
1260 nsresult rv;
1262 rv = NS_InitXPCOM2(&mServiceManager, gDirServiceProvider->GetAppDir(),
1263 gDirServiceProvider);
1264 if (NS_FAILED(rv)) {
1265 NS_ERROR("Couldn't start xpcom!");
1266 mServiceManager = nullptr;
1267 }
1268 else {
1269 nsCOMPtr<nsIComponentRegistrar> reg =
1270 do_QueryInterface(mServiceManager);
1271 NS_ASSERTION(reg, "Service Manager doesn't QI to Registrar.");
1272 }
1274 return rv;
1275 }
1277 /**
1278 * This is a little factory class that serves as a singleton-service-factory
1279 * for the nativeappsupport object.
1280 */
1281 class nsSingletonFactory MOZ_FINAL : public nsIFactory
1282 {
1283 public:
1284 NS_DECL_ISUPPORTS
1285 NS_DECL_NSIFACTORY
1287 nsSingletonFactory(nsISupports* aSingleton);
1288 ~nsSingletonFactory() { }
1290 private:
1291 nsCOMPtr<nsISupports> mSingleton;
1292 };
1294 nsSingletonFactory::nsSingletonFactory(nsISupports* aSingleton)
1295 : mSingleton(aSingleton)
1296 {
1297 NS_ASSERTION(mSingleton, "Singleton was null!");
1298 }
1300 NS_IMPL_ISUPPORTS(nsSingletonFactory, nsIFactory)
1302 NS_IMETHODIMP
1303 nsSingletonFactory::CreateInstance(nsISupports* aOuter,
1304 const nsIID& aIID,
1305 void* *aResult)
1306 {
1307 NS_ENSURE_NO_AGGREGATION(aOuter);
1309 return mSingleton->QueryInterface(aIID, aResult);
1310 }
1312 NS_IMETHODIMP
1313 nsSingletonFactory::LockFactory(bool)
1314 {
1315 return NS_OK;
1316 }
1318 /**
1319 * Set our windowcreator on the WindowWatcher service.
1320 */
1321 nsresult
1322 ScopedXPCOMStartup::SetWindowCreator(nsINativeAppSupport* native)
1323 {
1324 nsresult rv;
1326 NS_IF_ADDREF(gNativeAppSupport = native);
1328 // Inform the chrome registry about OS accessibility
1329 nsCOMPtr<nsIToolkitChromeRegistry> cr =
1330 mozilla::services::GetToolkitChromeRegistryService();
1332 if (cr)
1333 cr->CheckForOSAccessibility();
1335 nsCOMPtr<nsIWindowCreator> creator (do_GetService(NS_APPSTARTUP_CONTRACTID));
1336 if (!creator) return NS_ERROR_UNEXPECTED;
1338 nsCOMPtr<nsIWindowWatcher> wwatch
1339 (do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv));
1340 NS_ENSURE_SUCCESS(rv, rv);
1342 return wwatch->SetWindowCreator(creator);
1343 }
1345 /* static */ nsresult
1346 ScopedXPCOMStartup::CreateAppSupport(nsISupports* aOuter, REFNSIID aIID, void** aResult)
1347 {
1348 if (aOuter)
1349 return NS_ERROR_NO_AGGREGATION;
1351 if (!gNativeAppSupport)
1352 return NS_ERROR_NOT_INITIALIZED;
1354 return gNativeAppSupport->QueryInterface(aIID, aResult);
1355 }
1357 nsINativeAppSupport* ScopedXPCOMStartup::gNativeAppSupport;
1359 /**
1360 * A helper class which calls NS_LogInit/NS_LogTerm in its scope.
1361 */
1362 class ScopedLogging
1363 {
1364 public:
1365 ScopedLogging() { NS_LogInit(); }
1366 ~ScopedLogging() { NS_LogTerm(); }
1367 };
1369 static void DumpArbitraryHelp()
1370 {
1371 nsresult rv;
1373 ScopedLogging log;
1375 {
1376 ScopedXPCOMStartup xpcom;
1377 xpcom.Initialize();
1379 nsCOMPtr<nsICommandLineRunner> cmdline
1380 (do_CreateInstance("@mozilla.org/toolkit/command-line;1"));
1381 if (!cmdline)
1382 return;
1384 nsCString text;
1385 rv = cmdline->GetHelpText(text);
1386 if (NS_SUCCEEDED(rv))
1387 printf("%s", text.get());
1388 }
1389 }
1391 // English text needs to go into a dtd file.
1392 // But when this is called we have no components etc. These strings must either be
1393 // here, or in a native resource file.
1394 static void
1395 DumpHelp()
1396 {
1397 printf("Usage: %s [ options ... ] [URL]\n"
1398 " where options include:\n\n", gArgv[0]);
1400 #ifdef MOZ_X11
1401 printf("X11 options\n"
1402 " --display=DISPLAY X display to use\n"
1403 " --sync Make X calls synchronous\n");
1404 #endif
1405 #ifdef XP_UNIX
1406 printf(" --g-fatal-warnings Make all warnings fatal\n"
1407 "\n%s options\n", gAppData->name);
1408 #endif
1410 printf(" -h or -help Print this message.\n"
1411 " -v or -version Print %s version.\n"
1412 " -P <profile> Start with <profile>.\n"
1413 " -migration Start with migration wizard.\n"
1414 " -ProfileManager Start with ProfileManager.\n"
1415 " -no-remote (default) Do not accept or send remote commands; implies -new-instance.\n"
1416 " -allow-remote Accept and send remote commands.\n"
1417 " -new-instance Open new instance, not a new window in running instance.\n"
1418 " -UILocale <locale> Start with <locale> resources as UI Locale.\n"
1419 " -safe-mode Disables extensions and themes for this session.\n", gAppData->name);
1421 #if defined(XP_WIN)
1422 printf(" -console Start %s with a debugging console.\n", gAppData->name);
1423 #endif
1425 // this works, but only after the components have registered. so if you drop in a new command line handler, -help
1426 // won't not until the second run.
1427 // out of the bug, because we ship a component.reg file, it works correctly.
1428 DumpArbitraryHelp();
1429 }
1431 #if defined(DEBUG) && defined(XP_WIN)
1432 #ifdef DEBUG_warren
1433 #define _CRTDBG_MAP_ALLOC
1434 #endif
1435 // Set a CRT ReportHook function to capture and format MSCRT
1436 // warnings, errors and assertions.
1437 // See http://msdn.microsoft.com/en-US/library/74kabxyx(v=VS.80).aspx
1438 #include <stdio.h>
1439 #include <crtdbg.h>
1440 #include "mozilla/mozalloc_abort.h"
1441 static int MSCRTReportHook( int aReportType, char *aMessage, int *oReturnValue)
1442 {
1443 *oReturnValue = 0; // continue execution
1445 // Do not use fprintf or other functions which may allocate
1446 // memory from the heap which may be corrupted. Instead,
1447 // use fputs to output the leading portion of the message
1448 // and use mozalloc_abort to emit the remainder of the
1449 // message.
1451 switch(aReportType) {
1452 case 0:
1453 fputs("\nWARNING: CRT WARNING", stderr);
1454 fputs(aMessage, stderr);
1455 fputs("\n", stderr);
1456 break;
1457 case 1:
1458 fputs("\n###!!! ABORT: CRT ERROR ", stderr);
1459 mozalloc_abort(aMessage);
1460 break;
1461 case 2:
1462 fputs("\n###!!! ABORT: CRT ASSERT ", stderr);
1463 mozalloc_abort(aMessage);
1464 break;
1465 }
1467 // do not invoke the debugger
1468 return 1;
1469 }
1471 #endif
1473 static inline void
1474 DumpVersion()
1475 {
1476 if (gAppData->vendor)
1477 printf("%s ", gAppData->vendor);
1478 printf("%s %s", gAppData->name, gAppData->version);
1479 if (gAppData->copyright)
1480 printf(", %s", gAppData->copyright);
1481 printf("\n");
1482 }
1484 #ifdef MOZ_ENABLE_XREMOTE
1485 // use int here instead of a PR type since it will be returned
1486 // from main - just to keep types consistent
1487 static int
1488 HandleRemoteArgument(const char* remote, const char* aDesktopStartupID)
1489 {
1490 nsresult rv;
1491 ArgResult ar;
1493 const char *profile = 0;
1494 nsAutoCString program(gAppData->name);
1495 ToLowerCase(program);
1496 const char *username = getenv("LOGNAME");
1498 ar = CheckArg("p", false, &profile);
1499 if (ar == ARG_BAD) {
1500 PR_fprintf(PR_STDERR, "Error: argument -p requires a profile name\n");
1501 return 1;
1502 }
1504 const char *temp = nullptr;
1505 ar = CheckArg("a", false, &temp);
1506 if (ar == ARG_BAD) {
1507 PR_fprintf(PR_STDERR, "Error: argument -a requires an application name\n");
1508 return 1;
1509 } else if (ar == ARG_FOUND) {
1510 program.Assign(temp);
1511 }
1513 ar = CheckArg("u", false, &username);
1514 if (ar == ARG_BAD) {
1515 PR_fprintf(PR_STDERR, "Error: argument -u requires a username\n");
1516 return 1;
1517 }
1519 XRemoteClient client;
1520 rv = client.Init();
1521 if (NS_FAILED(rv)) {
1522 PR_fprintf(PR_STDERR, "Error: Failed to connect to X server.\n");
1523 return 1;
1524 }
1526 nsXPIDLCString response;
1527 bool success = false;
1528 rv = client.SendCommand(program.get(), username, profile, remote,
1529 aDesktopStartupID, getter_Copies(response), &success);
1530 // did the command fail?
1531 if (NS_FAILED(rv)) {
1532 PR_fprintf(PR_STDERR, "Error: Failed to send command: %s\n",
1533 response ? response.get() : "No response included");
1534 return 1;
1535 }
1537 if (!success) {
1538 PR_fprintf(PR_STDERR, "Error: No running window found\n");
1539 return 2;
1540 }
1542 return 0;
1543 }
1545 static RemoteResult
1546 RemoteCommandLine(const char* aDesktopStartupID)
1547 {
1548 nsresult rv;
1549 ArgResult ar;
1551 nsAutoCString program(gAppData->name);
1552 ToLowerCase(program);
1553 const char *username = getenv("LOGNAME");
1555 const char *temp = nullptr;
1556 ar = CheckArg("a", true, &temp);
1557 if (ar == ARG_BAD) {
1558 PR_fprintf(PR_STDERR, "Error: argument -a requires an application name\n");
1559 return REMOTE_ARG_BAD;
1560 } else if (ar == ARG_FOUND) {
1561 program.Assign(temp);
1562 }
1564 ar = CheckArg("u", true, &username);
1565 if (ar == ARG_BAD) {
1566 PR_fprintf(PR_STDERR, "Error: argument -u requires a username\n");
1567 return REMOTE_ARG_BAD;
1568 }
1570 XRemoteClient client;
1571 rv = client.Init();
1572 if (NS_FAILED(rv))
1573 return REMOTE_NOT_FOUND;
1575 nsXPIDLCString response;
1576 bool success = false;
1577 rv = client.SendCommandLine(program.get(), username, nullptr,
1578 gArgc, gArgv, aDesktopStartupID,
1579 getter_Copies(response), &success);
1580 // did the command fail?
1581 if (NS_FAILED(rv) || !success)
1582 return REMOTE_NOT_FOUND;
1584 return REMOTE_FOUND;
1585 }
1586 #endif // MOZ_ENABLE_XREMOTE
1588 void
1589 XRE_InitOmnijar(nsIFile* greOmni, nsIFile* appOmni)
1590 {
1591 mozilla::Omnijar::Init(greOmni, appOmni);
1592 }
1594 nsresult
1595 XRE_GetBinaryPath(const char* argv0, nsIFile* *aResult)
1596 {
1597 return mozilla::BinaryPath::GetFile(argv0, aResult);
1598 }
1600 #ifdef XP_WIN
1601 #include "nsWindowsRestart.cpp"
1602 #include <shellapi.h>
1604 typedef BOOL (WINAPI* SetProcessDEPPolicyFunc)(DWORD dwFlags);
1605 #endif
1607 // If aBlankCommandLine is true, then the application will be launched with a
1608 // blank command line instead of being launched with the same command line that
1609 // it was initially started with.
1610 static nsresult LaunchChild(nsINativeAppSupport* aNative,
1611 bool aBlankCommandLine = false)
1612 {
1613 aNative->Quit(); // release DDE mutex, if we're holding it
1615 // Restart this process by exec'ing it into the current process
1616 // if supported by the platform. Otherwise, use NSPR.
1618 #ifdef MOZ_JPROF
1619 // make sure JPROF doesn't think we're E10s
1620 unsetenv("JPROF_SLAVE");
1621 #endif
1623 if (aBlankCommandLine) {
1624 #if defined(MOZ_WIDGET_QT)
1625 // Remove only arguments not given to Qt
1626 gRestartArgc = gQtOnlyArgc;
1627 gRestartArgv = gQtOnlyArgv;
1628 #else
1629 gRestartArgc = 1;
1630 gRestartArgv[gRestartArgc] = nullptr;
1631 #endif
1632 }
1634 SaveToEnv("MOZ_LAUNCHED_CHILD=1");
1636 #if defined(MOZ_WIDGET_ANDROID)
1637 mozilla::widget::android::GeckoAppShell::ScheduleRestart();
1638 #else
1639 #if defined(XP_MACOSX)
1640 CommandLineServiceMac::SetupMacCommandLine(gRestartArgc, gRestartArgv, true);
1641 uint32_t restartMode = 0;
1642 restartMode = gRestartMode;
1643 LaunchChildMac(gRestartArgc, gRestartArgv, restartMode);
1644 #else
1645 nsCOMPtr<nsIFile> lf;
1646 nsresult rv = XRE_GetBinaryPath(gArgv[0], getter_AddRefs(lf));
1647 if (NS_FAILED(rv))
1648 return rv;
1650 #if defined(XP_WIN)
1651 nsAutoString exePath;
1652 rv = lf->GetPath(exePath);
1653 if (NS_FAILED(rv))
1654 return rv;
1656 if (!WinLaunchChild(exePath.get(), gRestartArgc, gRestartArgv))
1657 return NS_ERROR_FAILURE;
1659 #else
1660 nsAutoCString exePath;
1661 rv = lf->GetNativePath(exePath);
1662 if (NS_FAILED(rv))
1663 return rv;
1665 #if defined(XP_UNIX)
1666 if (execv(exePath.get(), gRestartArgv) == -1)
1667 return NS_ERROR_FAILURE;
1668 #else
1669 PRProcess* process = PR_CreateProcess(exePath.get(), gRestartArgv,
1670 nullptr, nullptr);
1671 if (!process) return NS_ERROR_FAILURE;
1673 int32_t exitCode;
1674 PRStatus failed = PR_WaitProcess(process, &exitCode);
1675 if (failed || exitCode)
1676 return NS_ERROR_FAILURE;
1677 #endif // XP_UNIX
1678 #endif // WP_WIN
1679 #endif // WP_MACOSX
1680 #endif // MOZ_WIDGET_ANDROID
1682 return NS_ERROR_LAUNCHED_CHILD_PROCESS;
1683 }
1685 static const char kProfileProperties[] =
1686 "chrome://mozapps/locale/profile/profileSelection.properties";
1688 static nsresult
1689 ProfileLockedDialog(nsIFile* aProfileDir, nsIFile* aProfileLocalDir,
1690 nsIProfileUnlocker* aUnlocker,
1691 nsINativeAppSupport* aNative, nsIProfileLock* *aResult)
1692 {
1693 nsresult rv;
1695 ScopedXPCOMStartup xpcom;
1696 rv = xpcom.Initialize();
1697 NS_ENSURE_SUCCESS(rv, rv);
1699 mozilla::Telemetry::WriteFailedProfileLock(aProfileDir);
1701 rv = xpcom.SetWindowCreator(aNative);
1702 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
1704 { //extra scoping is needed so we release these components before xpcom shutdown
1705 nsCOMPtr<nsIStringBundleService> sbs =
1706 mozilla::services::GetStringBundleService();
1707 NS_ENSURE_TRUE(sbs, NS_ERROR_FAILURE);
1709 nsCOMPtr<nsIStringBundle> sb;
1710 sbs->CreateBundle(kProfileProperties, getter_AddRefs(sb));
1711 NS_ENSURE_TRUE_LOG(sbs, NS_ERROR_FAILURE);
1713 NS_ConvertUTF8toUTF16 appName(gAppData->name);
1714 const char16_t* params[] = {appName.get(), appName.get()};
1716 nsXPIDLString killMessage;
1717 #ifndef XP_MACOSX
1718 static const char16_t kRestartNoUnlocker[] = {'r','e','s','t','a','r','t','M','e','s','s','a','g','e','N','o','U','n','l','o','c','k','e','r','\0'}; // "restartMessageNoUnlocker"
1719 static const char16_t kRestartUnlocker[] = {'r','e','s','t','a','r','t','M','e','s','s','a','g','e','U','n','l','o','c','k','e','r','\0'}; // "restartMessageUnlocker"
1720 #else
1721 static const char16_t kRestartNoUnlocker[] = {'r','e','s','t','a','r','t','M','e','s','s','a','g','e','N','o','U','n','l','o','c','k','e','r','M','a','c','\0'}; // "restartMessageNoUnlockerMac"
1722 static const char16_t kRestartUnlocker[] = {'r','e','s','t','a','r','t','M','e','s','s','a','g','e','U','n','l','o','c','k','e','r','M','a','c','\0'}; // "restartMessageUnlockerMac"
1723 #endif
1725 sb->FormatStringFromName(aUnlocker ? kRestartUnlocker : kRestartNoUnlocker,
1726 params, 2, getter_Copies(killMessage));
1728 nsXPIDLString killTitle;
1729 sb->FormatStringFromName(MOZ_UTF16("restartTitle"),
1730 params, 1, getter_Copies(killTitle));
1732 if (!killMessage || !killTitle)
1733 return NS_ERROR_FAILURE;
1735 nsCOMPtr<nsIPromptService> ps
1736 (do_GetService(NS_PROMPTSERVICE_CONTRACTID));
1737 NS_ENSURE_TRUE(ps, NS_ERROR_FAILURE);
1739 if (aUnlocker) {
1740 int32_t button;
1741 #ifdef MOZ_WIDGET_ANDROID
1742 mozilla::widget::android::GeckoAppShell::KillAnyZombies();
1743 button = 1;
1744 #else
1745 const uint32_t flags =
1746 (nsIPromptService::BUTTON_TITLE_CANCEL *
1747 nsIPromptService::BUTTON_POS_0) +
1748 (nsIPromptService::BUTTON_TITLE_IS_STRING *
1749 nsIPromptService::BUTTON_POS_1) +
1750 nsIPromptService::BUTTON_POS_1_DEFAULT;
1752 bool checkState = false;
1753 rv = ps->ConfirmEx(nullptr, killTitle, killMessage, flags,
1754 killTitle, nullptr, nullptr, nullptr,
1755 &checkState, &button);
1756 NS_ENSURE_SUCCESS_LOG(rv, rv);
1757 #endif
1759 if (button == 1) {
1760 rv = aUnlocker->Unlock(nsIProfileUnlocker::FORCE_QUIT);
1761 if (NS_FAILED(rv))
1762 return rv;
1764 return NS_LockProfilePath(aProfileDir, aProfileLocalDir,
1765 nullptr, aResult);
1766 }
1767 } else {
1768 #ifdef MOZ_WIDGET_ANDROID
1769 if (mozilla::widget::android::GeckoAppShell::UnlockProfile()) {
1770 return NS_LockProfilePath(aProfileDir, aProfileLocalDir,
1771 nullptr, aResult);
1772 }
1773 #else
1774 rv = ps->Alert(nullptr, killTitle, killMessage);
1775 NS_ENSURE_SUCCESS_LOG(rv, rv);
1776 #endif
1777 }
1779 return NS_ERROR_ABORT;
1780 }
1781 }
1784 static nsresult
1785 ProfileMissingDialog(nsINativeAppSupport* aNative)
1786 {
1787 nsresult rv;
1789 ScopedXPCOMStartup xpcom;
1790 rv = xpcom.Initialize();
1791 NS_ENSURE_SUCCESS(rv, rv);
1793 rv = xpcom.SetWindowCreator(aNative);
1794 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
1796 { //extra scoping is needed so we release these components before xpcom shutdown
1797 nsCOMPtr<nsIStringBundleService> sbs =
1798 mozilla::services::GetStringBundleService();
1799 NS_ENSURE_TRUE(sbs, NS_ERROR_FAILURE);
1801 nsCOMPtr<nsIStringBundle> sb;
1802 sbs->CreateBundle(kProfileProperties, getter_AddRefs(sb));
1803 NS_ENSURE_TRUE_LOG(sbs, NS_ERROR_FAILURE);
1805 NS_ConvertUTF8toUTF16 appName(gAppData->name);
1806 const char16_t* params[] = {appName.get(), appName.get()};
1808 nsXPIDLString missingMessage;
1810 // profileMissing
1811 static const char16_t kMissing[] = {'p','r','o','f','i','l','e','M','i','s','s','i','n','g','\0'};
1812 sb->FormatStringFromName(kMissing, params, 2, getter_Copies(missingMessage));
1814 nsXPIDLString missingTitle;
1815 sb->FormatStringFromName(MOZ_UTF16("profileMissingTitle"),
1816 params, 1, getter_Copies(missingTitle));
1818 if (missingMessage && missingTitle) {
1819 nsCOMPtr<nsIPromptService> ps
1820 (do_GetService(NS_PROMPTSERVICE_CONTRACTID));
1821 NS_ENSURE_TRUE(ps, NS_ERROR_FAILURE);
1823 ps->Alert(nullptr, missingTitle, missingMessage);
1824 }
1826 return NS_ERROR_ABORT;
1827 }
1828 }
1830 static nsresult
1831 ProfileLockedDialog(nsIToolkitProfile* aProfile, nsIProfileUnlocker* aUnlocker,
1832 nsINativeAppSupport* aNative, nsIProfileLock* *aResult)
1833 {
1834 nsCOMPtr<nsIFile> profileDir;
1835 nsresult rv = aProfile->GetRootDir(getter_AddRefs(profileDir));
1836 if (NS_FAILED(rv)) return rv;
1838 bool exists;
1839 profileDir->Exists(&exists);
1840 if (!exists) {
1841 return ProfileMissingDialog(aNative);
1842 }
1844 nsCOMPtr<nsIFile> profileLocalDir;
1845 rv = aProfile->GetLocalDir(getter_AddRefs(profileLocalDir));
1846 if (NS_FAILED(rv)) return rv;
1848 return ProfileLockedDialog(profileDir, profileLocalDir, aUnlocker, aNative,
1849 aResult);
1850 }
1852 static const char kProfileManagerURL[] =
1853 "chrome://mozapps/content/profile/profileSelection.xul";
1855 static nsresult
1856 ShowProfileManager(nsIToolkitProfileService* aProfileSvc,
1857 nsINativeAppSupport* aNative)
1858 {
1859 if (!CanShowProfileManager()) {
1860 return NS_ERROR_NOT_IMPLEMENTED;
1861 }
1863 nsresult rv;
1865 nsCOMPtr<nsIFile> profD, profLD;
1866 char16_t* profileNamePtr;
1867 nsAutoCString profileName;
1869 {
1870 ScopedXPCOMStartup xpcom;
1871 rv = xpcom.Initialize();
1872 NS_ENSURE_SUCCESS(rv, rv);
1874 rv = xpcom.SetWindowCreator(aNative);
1875 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
1877 #ifdef XP_MACOSX
1878 CommandLineServiceMac::SetupMacCommandLine(gRestartArgc, gRestartArgv, true);
1879 #endif
1881 #ifdef XP_WIN
1882 // we don't have to wait here because profile manager window will pump
1883 // and DDE message will be handled
1884 ProcessDDE(aNative, false);
1885 #endif
1887 { //extra scoping is needed so we release these components before xpcom shutdown
1888 nsCOMPtr<nsIWindowWatcher> windowWatcher
1889 (do_GetService(NS_WINDOWWATCHER_CONTRACTID));
1890 nsCOMPtr<nsIDialogParamBlock> ioParamBlock
1891 (do_CreateInstance(NS_DIALOGPARAMBLOCK_CONTRACTID));
1892 nsCOMPtr<nsIMutableArray> dlgArray (do_CreateInstance(NS_ARRAY_CONTRACTID));
1893 NS_ENSURE_TRUE(windowWatcher && ioParamBlock && dlgArray, NS_ERROR_FAILURE);
1895 ioParamBlock->SetObjects(dlgArray);
1897 nsCOMPtr<nsIAppStartup> appStartup
1898 (do_GetService(NS_APPSTARTUP_CONTRACTID));
1899 NS_ENSURE_TRUE(appStartup, NS_ERROR_FAILURE);
1901 nsCOMPtr<nsIDOMWindow> newWindow;
1902 rv = windowWatcher->OpenWindow(nullptr,
1903 kProfileManagerURL,
1904 "_blank",
1905 "centerscreen,chrome,modal,titlebar",
1906 ioParamBlock,
1907 getter_AddRefs(newWindow));
1909 NS_ENSURE_SUCCESS_LOG(rv, rv);
1911 aProfileSvc->Flush();
1913 int32_t dialogConfirmed;
1914 rv = ioParamBlock->GetInt(0, &dialogConfirmed);
1915 if (NS_FAILED(rv) || dialogConfirmed == 0) return NS_ERROR_ABORT;
1917 nsCOMPtr<nsIProfileLock> lock;
1918 rv = dlgArray->QueryElementAt(0, NS_GET_IID(nsIProfileLock),
1919 getter_AddRefs(lock));
1920 NS_ENSURE_SUCCESS_LOG(rv, rv);
1922 rv = lock->GetDirectory(getter_AddRefs(profD));
1923 NS_ENSURE_SUCCESS(rv, rv);
1925 rv = lock->GetLocalDirectory(getter_AddRefs(profLD));
1926 NS_ENSURE_SUCCESS(rv, rv);
1928 rv = ioParamBlock->GetString(0, &profileNamePtr);
1929 NS_ENSURE_SUCCESS(rv, rv);
1931 CopyUTF16toUTF8(profileNamePtr, profileName);
1932 NS_Free(profileNamePtr);
1934 lock->Unlock();
1935 }
1936 }
1938 SaveFileToEnv("XRE_PROFILE_PATH", profD);
1939 SaveFileToEnv("XRE_PROFILE_LOCAL_PATH", profLD);
1940 SaveWordToEnv("XRE_PROFILE_NAME", profileName);
1942 bool offline = false;
1943 aProfileSvc->GetStartOffline(&offline);
1944 if (offline) {
1945 SaveToEnv("XRE_START_OFFLINE=1");
1946 }
1948 return LaunchChild(aNative);
1949 }
1951 static nsresult
1952 GetCurrentProfileIsDefault(nsIToolkitProfileService* aProfileSvc,
1953 nsIFile* aCurrentProfileRoot, bool *aResult)
1954 {
1955 nsresult rv;
1956 // Check that the profile to reset is the default since reset and the associated migration are
1957 // only supported in that case.
1958 nsCOMPtr<nsIToolkitProfile> selectedProfile;
1959 nsCOMPtr<nsIFile> selectedProfileRoot;
1960 rv = aProfileSvc->GetSelectedProfile(getter_AddRefs(selectedProfile));
1961 NS_ENSURE_SUCCESS(rv, rv);
1963 rv = selectedProfile->GetRootDir(getter_AddRefs(selectedProfileRoot));
1964 NS_ENSURE_SUCCESS(rv, rv);
1966 bool currentIsSelected;
1967 rv = aCurrentProfileRoot->Equals(selectedProfileRoot, ¤tIsSelected);
1969 *aResult = currentIsSelected;
1970 return rv;
1971 }
1973 /**
1974 * Set the currently running profile as the default/selected one.
1975 *
1976 * @param aCurrentProfileRoot The root directory of the current profile.
1977 * @return an error if aCurrentProfileRoot is not found or the profile could not
1978 * be set as the default.
1979 */
1980 static nsresult
1981 SetCurrentProfileAsDefault(nsIToolkitProfileService* aProfileSvc,
1982 nsIFile* aCurrentProfileRoot)
1983 {
1984 NS_ENSURE_ARG_POINTER(aProfileSvc);
1986 nsCOMPtr<nsISimpleEnumerator> profiles;
1987 nsresult rv = aProfileSvc->GetProfiles(getter_AddRefs(profiles));
1988 if (NS_FAILED(rv))
1989 return rv;
1991 bool foundMatchingProfile = false;
1992 nsCOMPtr<nsISupports> supports;
1993 rv = profiles->GetNext(getter_AddRefs(supports));
1994 while (NS_SUCCEEDED(rv)) {
1995 nsCOMPtr<nsIToolkitProfile> profile = do_QueryInterface(supports);
1996 nsCOMPtr<nsIFile> profileRoot;
1997 profile->GetRootDir(getter_AddRefs(profileRoot));
1998 profileRoot->Equals(aCurrentProfileRoot, &foundMatchingProfile);
1999 if (foundMatchingProfile && profile) {
2000 rv = aProfileSvc->SetSelectedProfile(profile);
2001 if (NS_SUCCEEDED(rv))
2002 rv = aProfileSvc->Flush();
2003 return rv;
2004 }
2005 rv = profiles->GetNext(getter_AddRefs(supports));
2006 }
2007 return rv;
2008 }
2010 static bool gDoMigration = false;
2011 static bool gDoProfileReset = false;
2013 // Pick a profile. We need to end up with a profile lock.
2014 //
2015 // 1) check for -profile <path>
2016 // 2) check for -P <name>
2017 // 3) check for -ProfileManager
2018 // 4) use the default profile, if there is one
2019 // 5) if there are *no* profiles, set up profile-migration
2020 // 6) display the profile-manager UI
2021 static nsresult
2022 SelectProfile(nsIProfileLock* *aResult, nsIToolkitProfileService* aProfileSvc, nsINativeAppSupport* aNative,
2023 bool* aStartOffline, nsACString* aProfileName)
2024 {
2025 StartupTimeline::Record(StartupTimeline::SELECT_PROFILE);
2027 nsresult rv;
2028 ArgResult ar;
2029 const char* arg;
2030 *aResult = nullptr;
2031 *aStartOffline = false;
2033 ar = CheckArg("offline", true);
2034 if (ar == ARG_BAD) {
2035 PR_fprintf(PR_STDERR, "Error: argument -offline is invalid when argument -osint is specified\n");
2036 return NS_ERROR_FAILURE;
2037 }
2039 if (ar || EnvHasValue("XRE_START_OFFLINE"))
2040 *aStartOffline = true;
2042 if (EnvHasValue("MOZ_RESET_PROFILE_RESTART")) {
2043 gDoProfileReset = true;
2044 gDoMigration = true;
2045 SaveToEnv("MOZ_RESET_PROFILE_RESTART=");
2046 }
2048 // reset-profile and migration args need to be checked before any profiles are chosen below.
2049 ar = CheckArg("reset-profile", true);
2050 if (ar == ARG_BAD) {
2051 PR_fprintf(PR_STDERR, "Error: argument -reset-profile is invalid when argument -osint is specified\n");
2052 return NS_ERROR_FAILURE;
2053 } else if (ar == ARG_FOUND) {
2054 gDoProfileReset = true;
2055 }
2057 ar = CheckArg("migration", true);
2058 if (ar == ARG_BAD) {
2059 PR_fprintf(PR_STDERR, "Error: argument -migration is invalid when argument -osint is specified\n");
2060 return NS_ERROR_FAILURE;
2061 } else if (ar == ARG_FOUND) {
2062 gDoMigration = true;
2063 }
2065 nsCOMPtr<nsIFile> lf = GetFileFromEnv("XRE_PROFILE_PATH");
2066 if (lf) {
2067 nsCOMPtr<nsIFile> localDir =
2068 GetFileFromEnv("XRE_PROFILE_LOCAL_PATH");
2069 if (!localDir) {
2070 localDir = lf;
2071 }
2073 arg = PR_GetEnv("XRE_PROFILE_NAME");
2074 if (arg && *arg && aProfileName)
2075 aProfileName->Assign(nsDependentCString(arg));
2077 // Clear out flags that we handled (or should have handled!) last startup.
2078 const char *dummy;
2079 CheckArg("p", false, &dummy);
2080 CheckArg("profile", false, &dummy);
2081 CheckArg("profilemanager");
2083 if (gDoProfileReset) {
2084 // Check that the profile to reset is the default since reset and migration are only
2085 // supported in that case.
2086 bool currentIsSelected;
2087 GetCurrentProfileIsDefault(aProfileSvc, lf, ¤tIsSelected);
2088 if (!currentIsSelected) {
2089 NS_WARNING("Profile reset is only supported for the default profile.");
2090 gDoProfileReset = gDoMigration = false;
2091 }
2093 // If we're resetting a profile, create a new one and use it to startup.
2094 nsCOMPtr<nsIToolkitProfile> newProfile;
2095 rv = CreateResetProfile(aProfileSvc, getter_AddRefs(newProfile));
2096 if (NS_SUCCEEDED(rv)) {
2097 rv = newProfile->GetRootDir(getter_AddRefs(lf));
2098 NS_ENSURE_SUCCESS(rv, rv);
2099 SaveFileToEnv("XRE_PROFILE_PATH", lf);
2101 rv = newProfile->GetLocalDir(getter_AddRefs(localDir));
2102 NS_ENSURE_SUCCESS(rv, rv);
2103 SaveFileToEnv("XRE_PROFILE_LOCAL_PATH", localDir);
2105 rv = newProfile->GetName(*aProfileName);
2106 if (NS_FAILED(rv))
2107 aProfileName->Truncate(0);
2108 SaveWordToEnv("XRE_PROFILE_NAME", *aProfileName);
2109 } else {
2110 NS_WARNING("Profile reset failed.");
2111 gDoProfileReset = false;
2112 }
2113 }
2115 return NS_LockProfilePath(lf, localDir, nullptr, aResult);
2116 }
2118 ar = CheckArg("profile", true, &arg);
2119 if (ar == ARG_BAD) {
2120 PR_fprintf(PR_STDERR, "Error: argument -profile requires a path\n");
2121 return NS_ERROR_FAILURE;
2122 }
2123 if (ar) {
2124 if (gDoProfileReset) {
2125 NS_WARNING("Profile reset is only supported for the default profile.");
2126 gDoProfileReset = false;
2127 }
2129 nsCOMPtr<nsIFile> lf;
2130 rv = XRE_GetFileFromPath(arg, getter_AddRefs(lf));
2131 NS_ENSURE_SUCCESS(rv, rv);
2133 nsCOMPtr<nsIProfileUnlocker> unlocker;
2135 // Check if the profile path exists and it's a directory.
2136 bool exists;
2137 lf->Exists(&exists);
2138 if (!exists) {
2139 rv = lf->Create(nsIFile::DIRECTORY_TYPE, 0700);
2140 NS_ENSURE_SUCCESS(rv, rv);
2141 }
2143 // If a profile path is specified directory on the command line, then
2144 // assume that the temp directory is the same as the given directory.
2145 rv = NS_LockProfilePath(lf, lf, getter_AddRefs(unlocker), aResult);
2146 if (NS_SUCCEEDED(rv))
2147 return rv;
2149 return ProfileLockedDialog(lf, lf, unlocker, aNative, aResult);
2150 }
2152 ar = CheckArg("createprofile", true, &arg);
2153 if (ar == ARG_BAD) {
2154 PR_fprintf(PR_STDERR, "Error: argument -createprofile requires a profile name\n");
2155 return NS_ERROR_FAILURE;
2156 }
2157 if (ar) {
2158 nsCOMPtr<nsIToolkitProfile> profile;
2160 const char* delim = strchr(arg, ' ');
2161 if (delim) {
2162 nsCOMPtr<nsIFile> lf;
2163 rv = NS_NewNativeLocalFile(nsDependentCString(delim + 1),
2164 true, getter_AddRefs(lf));
2165 if (NS_FAILED(rv)) {
2166 PR_fprintf(PR_STDERR, "Error: profile path not valid.\n");
2167 return rv;
2168 }
2170 // As with -profile, assume that the given path will be used for the
2171 // main profile directory.
2172 rv = aProfileSvc->CreateProfile(lf, nsDependentCSubstring(arg, delim),
2173 getter_AddRefs(profile));
2174 } else {
2175 rv = aProfileSvc->CreateProfile(nullptr, nsDependentCString(arg),
2176 getter_AddRefs(profile));
2177 }
2178 // Some pathological arguments can make it this far
2179 if (NS_FAILED(rv)) {
2180 PR_fprintf(PR_STDERR, "Error creating profile.\n");
2181 return rv;
2182 }
2183 rv = NS_ERROR_ABORT;
2184 aProfileSvc->Flush();
2186 // XXXben need to ensure prefs.js exists here so the tinderboxes will
2187 // not go orange.
2188 nsCOMPtr<nsIFile> prefsJSFile;
2189 profile->GetRootDir(getter_AddRefs(prefsJSFile));
2190 prefsJSFile->AppendNative(NS_LITERAL_CSTRING("prefs.js"));
2191 nsAutoCString pathStr;
2192 prefsJSFile->GetNativePath(pathStr);
2193 PR_fprintf(PR_STDERR, "Success: created profile '%s' at '%s'\n", arg, pathStr.get());
2194 bool exists;
2195 prefsJSFile->Exists(&exists);
2196 if (!exists)
2197 prefsJSFile->Create(nsIFile::NORMAL_FILE_TYPE, 0644);
2198 // XXXdarin perhaps 0600 would be better?
2200 return rv;
2201 }
2203 uint32_t count;
2204 rv = aProfileSvc->GetProfileCount(&count);
2205 NS_ENSURE_SUCCESS(rv, rv);
2207 ar = CheckArg("p", false, &arg);
2208 if (ar == ARG_BAD) {
2209 ar = CheckArg("osint");
2210 if (ar == ARG_FOUND) {
2211 PR_fprintf(PR_STDERR, "Error: argument -p is invalid when argument -osint is specified\n");
2212 return NS_ERROR_FAILURE;
2213 }
2215 if (CanShowProfileManager()) {
2216 return ShowProfileManager(aProfileSvc, aNative);
2217 }
2218 }
2219 if (ar) {
2220 ar = CheckArg("osint");
2221 if (ar == ARG_FOUND) {
2222 PR_fprintf(PR_STDERR, "Error: argument -p is invalid when argument -osint is specified\n");
2223 return NS_ERROR_FAILURE;
2224 }
2225 nsCOMPtr<nsIToolkitProfile> profile;
2226 rv = aProfileSvc->GetProfileByName(nsDependentCString(arg),
2227 getter_AddRefs(profile));
2228 if (NS_SUCCEEDED(rv)) {
2229 if (gDoProfileReset) {
2230 NS_WARNING("Profile reset is only supported for the default profile.");
2231 gDoProfileReset = false;
2232 }
2234 nsCOMPtr<nsIProfileUnlocker> unlocker;
2235 rv = profile->Lock(getter_AddRefs(unlocker), aResult);
2236 if (NS_SUCCEEDED(rv)) {
2237 if (aProfileName)
2238 aProfileName->Assign(nsDependentCString(arg));
2239 return NS_OK;
2240 }
2242 return ProfileLockedDialog(profile, unlocker, aNative, aResult);
2243 }
2245 if (CanShowProfileManager()) {
2246 return ShowProfileManager(aProfileSvc, aNative);
2247 }
2248 }
2250 ar = CheckArg("profilemanager", true);
2251 if (ar == ARG_BAD) {
2252 PR_fprintf(PR_STDERR, "Error: argument -profilemanager is invalid when argument -osint is specified\n");
2253 return NS_ERROR_FAILURE;
2254 } else if (ar == ARG_FOUND && CanShowProfileManager()) {
2255 return ShowProfileManager(aProfileSvc, aNative);
2256 }
2258 if (!count) {
2259 gDoMigration = true;
2260 gDoProfileReset = false;
2262 // create a default profile
2263 nsCOMPtr<nsIToolkitProfile> profile;
2264 nsresult rv = aProfileSvc->CreateProfile(nullptr, // choose a default dir for us
2265 NS_LITERAL_CSTRING("default"),
2266 getter_AddRefs(profile));
2267 if (NS_SUCCEEDED(rv)) {
2268 aProfileSvc->Flush();
2269 rv = profile->Lock(nullptr, aResult);
2270 if (NS_SUCCEEDED(rv)) {
2271 if (aProfileName)
2272 aProfileName->Assign(NS_LITERAL_CSTRING("default"));
2273 return NS_OK;
2274 }
2275 }
2276 }
2278 bool useDefault = true;
2279 if (count > 1 && CanShowProfileManager()) {
2280 aProfileSvc->GetStartWithLastProfile(&useDefault);
2281 }
2283 if (useDefault) {
2284 nsCOMPtr<nsIToolkitProfile> profile;
2285 // GetSelectedProfile will auto-select the only profile if there's just one
2286 aProfileSvc->GetSelectedProfile(getter_AddRefs(profile));
2287 if (profile) {
2288 // If we're resetting a profile, create a new one and use it to startup.
2289 if (gDoProfileReset) {
2290 {
2291 // Check that the source profile is not in use by temporarily acquiring its lock.
2292 nsIProfileLock* tempProfileLock;
2293 nsCOMPtr<nsIProfileUnlocker> unlocker;
2294 rv = profile->Lock(getter_AddRefs(unlocker), &tempProfileLock);
2295 if (NS_FAILED(rv))
2296 return ProfileLockedDialog(profile, unlocker, aNative, &tempProfileLock);
2297 }
2299 nsCOMPtr<nsIToolkitProfile> newProfile;
2300 rv = CreateResetProfile(aProfileSvc, getter_AddRefs(newProfile));
2301 if (NS_SUCCEEDED(rv))
2302 profile = newProfile;
2303 else
2304 gDoProfileReset = false;
2305 }
2307 // If you close Firefox and very quickly reopen it, the old Firefox may
2308 // still be closing down. Rather than immediately showing the
2309 // "Firefox is running but is not responding" message, we spend a few
2310 // seconds retrying first.
2312 static const int kLockRetrySeconds = 5;
2313 static const int kLockRetrySleepMS = 100;
2315 nsCOMPtr<nsIProfileUnlocker> unlocker;
2316 const TimeStamp start = TimeStamp::Now();
2317 do {
2318 rv = profile->Lock(getter_AddRefs(unlocker), aResult);
2319 if (NS_SUCCEEDED(rv)) {
2320 StartupTimeline::Record(StartupTimeline::AFTER_PROFILE_LOCKED);
2321 // Try to grab the profile name.
2322 if (aProfileName) {
2323 rv = profile->GetName(*aProfileName);
2324 if (NS_FAILED(rv))
2325 aProfileName->Truncate(0);
2326 }
2327 return NS_OK;
2328 }
2329 PR_Sleep(kLockRetrySleepMS);
2330 } while (TimeStamp::Now() - start < TimeDuration::FromSeconds(kLockRetrySeconds));
2332 return ProfileLockedDialog(profile, unlocker, aNative, aResult);
2333 }
2334 }
2336 if (!CanShowProfileManager()) {
2337 return NS_ERROR_FAILURE;
2338 }
2340 return ShowProfileManager(aProfileSvc, aNative);
2341 }
2343 /**
2344 * Checks the compatibility.ini file to see if we have updated our application
2345 * or otherwise invalidated our caches. If the application has been updated,
2346 * we return false; otherwise, we return true. We also write the status
2347 * of the caches (valid/invalid) into the return param aCachesOK. The aCachesOK
2348 * is always invalid if the application has been updated.
2349 */
2350 static bool
2351 CheckCompatibility(nsIFile* aProfileDir, const nsCString& aVersion,
2352 const nsCString& aOSABI, nsIFile* aXULRunnerDir,
2353 nsIFile* aAppDir, nsIFile* aFlagFile,
2354 bool* aCachesOK)
2355 {
2356 *aCachesOK = false;
2357 nsCOMPtr<nsIFile> file;
2358 aProfileDir->Clone(getter_AddRefs(file));
2359 if (!file)
2360 return false;
2361 file->AppendNative(FILE_COMPATIBILITY_INFO);
2363 nsINIParser parser;
2364 nsresult rv = parser.Init(file);
2365 if (NS_FAILED(rv))
2366 return false;
2368 nsAutoCString buf;
2369 rv = parser.GetString("Compatibility", "LastVersion", buf);
2370 if (NS_FAILED(rv) || !aVersion.Equals(buf))
2371 return false;
2373 rv = parser.GetString("Compatibility", "LastOSABI", buf);
2374 if (NS_FAILED(rv) || !aOSABI.Equals(buf))
2375 return false;
2377 rv = parser.GetString("Compatibility", "LastPlatformDir", buf);
2378 if (NS_FAILED(rv))
2379 return false;
2381 nsCOMPtr<nsIFile> lf;
2382 rv = NS_NewNativeLocalFile(buf, false,
2383 getter_AddRefs(lf));
2384 if (NS_FAILED(rv))
2385 return false;
2387 bool eq;
2388 rv = lf->Equals(aXULRunnerDir, &eq);
2389 if (NS_FAILED(rv) || !eq)
2390 return false;
2392 if (aAppDir) {
2393 rv = parser.GetString("Compatibility", "LastAppDir", buf);
2394 if (NS_FAILED(rv))
2395 return false;
2397 rv = NS_NewNativeLocalFile(buf, false,
2398 getter_AddRefs(lf));
2399 if (NS_FAILED(rv))
2400 return false;
2402 rv = lf->Equals(aAppDir, &eq);
2403 if (NS_FAILED(rv) || !eq)
2404 return false;
2405 }
2407 // If we see this flag, caches are invalid.
2408 rv = parser.GetString("Compatibility", "InvalidateCaches", buf);
2409 *aCachesOK = (NS_FAILED(rv) || !buf.EqualsLiteral("1"));
2411 bool purgeCaches = false;
2412 if (aFlagFile) {
2413 aFlagFile->Exists(&purgeCaches);
2414 }
2416 *aCachesOK = !purgeCaches && *aCachesOK;
2417 return true;
2418 }
2420 static void BuildVersion(nsCString &aBuf)
2421 {
2422 aBuf.Assign(gAppData->version);
2423 aBuf.Append('_');
2424 aBuf.Append(gAppData->buildID);
2425 aBuf.Append('/');
2426 aBuf.Append(gToolkitBuildID);
2427 }
2429 static void
2430 WriteVersion(nsIFile* aProfileDir, const nsCString& aVersion,
2431 const nsCString& aOSABI, nsIFile* aXULRunnerDir,
2432 nsIFile* aAppDir, bool invalidateCache)
2433 {
2434 nsCOMPtr<nsIFile> file;
2435 aProfileDir->Clone(getter_AddRefs(file));
2436 if (!file)
2437 return;
2438 file->AppendNative(FILE_COMPATIBILITY_INFO);
2440 nsAutoCString platformDir;
2441 aXULRunnerDir->GetNativePath(platformDir);
2443 nsAutoCString appDir;
2444 if (aAppDir)
2445 aAppDir->GetNativePath(appDir);
2447 PRFileDesc *fd = nullptr;
2448 file->OpenNSPRFileDesc(PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, 0600, &fd);
2449 if (!fd) {
2450 NS_ERROR("could not create output stream");
2451 return;
2452 }
2454 static const char kHeader[] = "[Compatibility]" NS_LINEBREAK
2455 "LastVersion=";
2457 PR_Write(fd, kHeader, sizeof(kHeader) - 1);
2458 PR_Write(fd, aVersion.get(), aVersion.Length());
2460 static const char kOSABIHeader[] = NS_LINEBREAK "LastOSABI=";
2461 PR_Write(fd, kOSABIHeader, sizeof(kOSABIHeader) - 1);
2462 PR_Write(fd, aOSABI.get(), aOSABI.Length());
2464 static const char kPlatformDirHeader[] = NS_LINEBREAK "LastPlatformDir=";
2466 PR_Write(fd, kPlatformDirHeader, sizeof(kPlatformDirHeader) - 1);
2467 PR_Write(fd, platformDir.get(), platformDir.Length());
2469 static const char kAppDirHeader[] = NS_LINEBREAK "LastAppDir=";
2470 if (aAppDir) {
2471 PR_Write(fd, kAppDirHeader, sizeof(kAppDirHeader) - 1);
2472 PR_Write(fd, appDir.get(), appDir.Length());
2473 }
2475 static const char kInvalidationHeader[] = NS_LINEBREAK "InvalidateCaches=1";
2476 if (invalidateCache)
2477 PR_Write(fd, kInvalidationHeader, sizeof(kInvalidationHeader) - 1);
2479 static const char kNL[] = NS_LINEBREAK;
2480 PR_Write(fd, kNL, sizeof(kNL) - 1);
2482 PR_Close(fd);
2483 }
2485 /**
2486 * Returns true if the startup cache file was successfully removed.
2487 * Returns false if file->Clone fails at any point (OOM) or if unable
2488 * to remove the startup cache file. Note in particular the return value
2489 * is unaffected by a failure to remove extensions.ini
2490 */
2491 static bool
2492 RemoveComponentRegistries(nsIFile* aProfileDir, nsIFile* aLocalProfileDir,
2493 bool aRemoveEMFiles)
2494 {
2495 nsCOMPtr<nsIFile> file;
2496 aProfileDir->Clone(getter_AddRefs(file));
2497 if (!file)
2498 return false;
2500 if (aRemoveEMFiles) {
2501 file->SetNativeLeafName(NS_LITERAL_CSTRING("extensions.ini"));
2502 file->Remove(false);
2503 }
2505 aLocalProfileDir->Clone(getter_AddRefs(file));
2506 if (!file)
2507 return false;
2509 #if defined(XP_UNIX) || defined(XP_BEOS)
2510 #define PLATFORM_FASL_SUFFIX ".mfasl"
2511 #elif defined(XP_WIN)
2512 #define PLATFORM_FASL_SUFFIX ".mfl"
2513 #endif
2515 file->AppendNative(NS_LITERAL_CSTRING("XUL" PLATFORM_FASL_SUFFIX));
2516 file->Remove(false);
2518 file->SetNativeLeafName(NS_LITERAL_CSTRING("XPC" PLATFORM_FASL_SUFFIX));
2519 file->Remove(false);
2521 file->SetNativeLeafName(NS_LITERAL_CSTRING("startupCache"));
2522 nsresult rv = file->Remove(true);
2523 return NS_SUCCEEDED(rv) || rv == NS_ERROR_FILE_TARGET_DOES_NOT_EXIST;
2524 }
2526 // To support application initiated restart via nsIAppStartup.quit, we
2527 // need to save various environment variables, and then restore them
2528 // before re-launching the application.
2530 static struct SavedVar {
2531 const char *name;
2532 char *value;
2533 } gSavedVars[] = {
2534 {"XUL_APP_FILE", nullptr}
2535 };
2537 static void SaveStateForAppInitiatedRestart()
2538 {
2539 for (size_t i = 0; i < ArrayLength(gSavedVars); ++i) {
2540 const char *s = PR_GetEnv(gSavedVars[i].name);
2541 if (s)
2542 gSavedVars[i].value = PR_smprintf("%s=%s", gSavedVars[i].name, s);
2543 }
2544 }
2546 static void RestoreStateForAppInitiatedRestart()
2547 {
2548 for (size_t i = 0; i < ArrayLength(gSavedVars); ++i) {
2549 if (gSavedVars[i].value)
2550 PR_SetEnv(gSavedVars[i].value);
2551 }
2552 }
2554 #ifdef MOZ_CRASHREPORTER
2555 // When we first initialize the crash reporter we don't have a profile,
2556 // so we set the minidump path to $TEMP. Once we have a profile,
2557 // we set it to $PROFILE/minidumps, creating the directory
2558 // if needed.
2559 static void MakeOrSetMinidumpPath(nsIFile* profD)
2560 {
2561 nsCOMPtr<nsIFile> dumpD;
2562 profD->Clone(getter_AddRefs(dumpD));
2564 if(dumpD) {
2565 bool fileExists;
2566 //XXX: do some more error checking here
2567 dumpD->Append(NS_LITERAL_STRING("minidumps"));
2568 dumpD->Exists(&fileExists);
2569 if(!fileExists) {
2570 dumpD->Create(nsIFile::DIRECTORY_TYPE, 0700);
2571 }
2573 nsAutoString pathStr;
2574 if(NS_SUCCEEDED(dumpD->GetPath(pathStr)))
2575 CrashReporter::SetMinidumpPath(pathStr);
2576 }
2577 }
2578 #endif
2580 const nsXREAppData* gAppData = nullptr;
2582 #ifdef MOZ_WIDGET_GTK
2583 #include "prlink.h"
2584 typedef void (*_g_set_application_name_fn)(const gchar *application_name);
2585 typedef void (*_gtk_window_set_auto_startup_notification_fn)(gboolean setting);
2587 static PRFuncPtr FindFunction(const char* aName)
2588 {
2589 PRLibrary *lib = nullptr;
2590 PRFuncPtr result = PR_FindFunctionSymbolAndLibrary(aName, &lib);
2591 // Since the library was already loaded, we can safely unload it here.
2592 if (lib) {
2593 PR_UnloadLibrary(lib);
2594 }
2595 return result;
2596 }
2598 static void MOZ_gdk_display_close(GdkDisplay *display)
2599 {
2600 #if CLEANUP_MEMORY
2601 // XXX wallpaper for bug 417163: don't close the Display if we're using the
2602 // Qt theme because we crash (in Qt code) when using jemalloc.
2603 bool theme_is_qt = false;
2604 GtkSettings* settings =
2605 gtk_settings_get_for_screen(gdk_display_get_default_screen(display));
2606 gchar *theme_name;
2607 g_object_get(settings, "gtk-theme-name", &theme_name, nullptr);
2608 if (theme_name) {
2609 theme_is_qt = strcmp(theme_name, "Qt") == 0;
2610 if (theme_is_qt)
2611 NS_WARNING("wallpaper bug 417163 for Qt theme");
2612 g_free(theme_name);
2613 }
2615 // Get a (new) Pango context that holds a reference to the fontmap that
2616 // GTK has been using. gdk_pango_context_get() must be called while GTK
2617 // has a default display.
2618 PangoContext *pangoContext = gdk_pango_context_get();
2620 bool buggyCairoShutdown = cairo_version() < CAIRO_VERSION_ENCODE(1, 4, 0);
2622 if (!buggyCairoShutdown) {
2623 // We should shut down GDK before we shut down libraries it depends on
2624 // like Pango and cairo. But if cairo shutdown is buggy, we should
2625 // shut down cairo first otherwise it may crash because of dangling
2626 // references to Display objects (see bug 469831).
2627 if (!theme_is_qt)
2628 gdk_display_close(display);
2629 }
2631 // Clean up PangoCairo's default fontmap.
2632 // This pango_fc_font_map_shutdown call (and the associated code to
2633 // get the font map) really shouldn't be needed anymore, except that
2634 // it's needed to avoid having cairo_debug_reset_static_data fatally
2635 // assert if we've leaked other things that hold on to the fontmap,
2636 // which is something that currently happens in mochitest-plugins.
2637 // Even if it didn't happen in mochitest-plugins, we probably want to
2638 // avoid the crash-on-leak problem since it makes it harder to use
2639 // many of our leak tools to debug leaks.
2641 // This doesn't take a reference.
2642 PangoFontMap *fontmap = pango_context_get_font_map(pangoContext);
2643 // Do some shutdown of the fontmap, which releases the fonts, clearing a
2644 // bunch of circular references from the fontmap through the fonts back to
2645 // itself. The shutdown that this does is much less than what's done by
2646 // the fontmap's finalize, though.
2647 if (PANGO_IS_FC_FONT_MAP(fontmap))
2648 pango_fc_font_map_shutdown(PANGO_FC_FONT_MAP(fontmap));
2649 g_object_unref(pangoContext);
2651 // Tell PangoCairo to release its default fontmap.
2652 pango_cairo_font_map_set_default(nullptr);
2654 // cairo_debug_reset_static_data() is prototyped through cairo.h included
2655 // by gtk.h.
2656 #ifdef cairo_debug_reset_static_data
2657 #error "Looks like we're including Mozilla's cairo instead of system cairo"
2658 #endif
2659 cairo_debug_reset_static_data();
2660 // FIXME: Do we need to call this in non-GTK2 cases as well?
2661 FcFini();
2663 if (buggyCairoShutdown) {
2664 if (!theme_is_qt)
2665 gdk_display_close(display);
2666 }
2667 #else // not CLEANUP_MEMORY
2668 // Don't do anything to avoid running into driver bugs under XCloseDisplay().
2669 // See bug 973192.
2670 (void) display;
2671 #endif
2672 }
2673 #endif // MOZ_WIDGET_GTK2
2675 /**
2676 * NSPR will search for the "nspr_use_zone_allocator" symbol throughout
2677 * the process and use it to determine whether the application defines its own
2678 * memory allocator or not.
2679 *
2680 * Since most applications (e.g. Firefox and Thunderbird) don't use any special
2681 * allocators and therefore don't define this symbol, NSPR must search the
2682 * entire process, which reduces startup performance.
2683 *
2684 * By defining the symbol here, we can avoid the wasted lookup and hopefully
2685 * improve startup performance.
2686 */
2687 NS_VISIBILITY_DEFAULT PRBool nspr_use_zone_allocator = PR_FALSE;
2689 #ifdef CAIRO_HAS_DWRITE_FONT
2691 #include <dwrite.h>
2693 #ifdef DEBUG_DWRITE_STARTUP
2695 #define LOGREGISTRY(msg) LogRegistryEvent(msg)
2697 // for use when monitoring process
2698 static void LogRegistryEvent(const wchar_t *msg)
2699 {
2700 HKEY dummyKey;
2701 HRESULT hr;
2702 wchar_t buf[512];
2704 wsprintf(buf, L" log %s", msg);
2705 hr = RegOpenKeyEx(HKEY_LOCAL_MACHINE, buf, 0, KEY_READ, &dummyKey);
2706 if (SUCCEEDED(hr)) {
2707 RegCloseKey(dummyKey);
2708 }
2709 }
2710 #else
2712 #define LOGREGISTRY(msg)
2714 #endif
2716 static DWORD InitDwriteBG(LPVOID lpdwThreadParam)
2717 {
2718 SetThreadPriority(GetCurrentThread(), THREAD_MODE_BACKGROUND_BEGIN);
2719 LOGREGISTRY(L"loading dwrite.dll");
2720 HMODULE dwdll = LoadLibraryW(L"dwrite.dll");
2721 if (dwdll) {
2722 decltype(DWriteCreateFactory)* createDWriteFactory = (decltype(DWriteCreateFactory)*)
2723 GetProcAddress(dwdll, "DWriteCreateFactory");
2724 if (createDWriteFactory) {
2725 LOGREGISTRY(L"creating dwrite factory");
2726 IDWriteFactory *factory;
2727 HRESULT hr = createDWriteFactory(
2728 DWRITE_FACTORY_TYPE_SHARED,
2729 __uuidof(IDWriteFactory),
2730 reinterpret_cast<IUnknown**>(&factory));
2731 if (SUCCEEDED(hr)) {
2732 LOGREGISTRY(L"dwrite factory done");
2733 factory->Release();
2734 LOGREGISTRY(L"freed factory");
2735 } else {
2736 LOGREGISTRY(L"failed to create factory");
2737 }
2738 }
2739 }
2740 SetThreadPriority(GetCurrentThread(), THREAD_MODE_BACKGROUND_END);
2741 return 0;
2742 }
2743 #endif
2745 #ifdef USE_GLX_TEST
2746 bool fire_glxtest_process();
2747 #endif
2749 #if defined(XP_WIN) && defined(MOZ_METRO)
2750 #ifndef AHE_TYPE
2751 enum AHE_TYPE {
2752 AHE_DESKTOP = 0,
2753 AHE_IMMERSIVE = 1
2754 };
2755 #endif
2757 /*
2758 * The Windows launcher uses this value to decide what front end ui
2759 * to launch. We always launch the same ui unless the user
2760 * specifically asks to switch. Update the value on every startup
2761 * based on the environment requested.
2762 */
2763 void
2764 SetLastWinRunType(AHE_TYPE aType)
2765 {
2766 HKEY key;
2767 LONG result = RegOpenKeyExW(HKEY_CURRENT_USER,
2768 L"SOFTWARE\\Mozilla\\Firefox",
2769 0, KEY_WRITE, &key);
2770 if (result != ERROR_SUCCESS) {
2771 return;
2772 }
2773 DWORD value = (DWORD)aType;
2774 result = RegSetValueEx(key, L"MetroLastAHE", 0, REG_DWORD,
2775 reinterpret_cast<LPBYTE>(&value),
2776 sizeof(DWORD));
2777 RegCloseKey(key);
2778 }
2779 #endif // defined(XP_WIN) && defined(MOZ_METRO)
2781 #include "GeckoProfiler.h"
2783 // Encapsulates startup and shutdown state for XRE_main
2784 class XREMain
2785 {
2786 public:
2787 XREMain() :
2788 mScopedXPCom(nullptr)
2789 , mAppData(nullptr)
2790 , mStartOffline(false)
2791 , mShuttingDown(false)
2792 #ifdef MOZ_ENABLE_XREMOTE
2793 , mDisableRemote(false)
2794 #endif
2795 #if defined(MOZ_WIDGET_GTK)
2796 , mGdkDisplay(nullptr)
2797 #endif
2798 {};
2800 ~XREMain() {
2801 if (mAppData) {
2802 delete mAppData;
2803 }
2804 if (mScopedXPCom) {
2805 NS_WARNING("Scoped xpcom should have been deleted!");
2806 delete mScopedXPCom;
2807 }
2808 }
2810 int XRE_main(int argc, char* argv[], const nsXREAppData* aAppData);
2811 int XRE_mainInit(bool* aExitFlag);
2812 int XRE_mainStartup(bool* aExitFlag);
2813 nsresult XRE_mainRun();
2815 nsCOMPtr<nsINativeAppSupport> mNativeApp;
2816 nsCOMPtr<nsIToolkitProfileService> mProfileSvc;
2817 nsCOMPtr<nsIFile> mProfD;
2818 nsCOMPtr<nsIFile> mProfLD;
2819 nsCOMPtr<nsIProfileLock> mProfileLock;
2820 #ifdef MOZ_ENABLE_XREMOTE
2821 nsCOMPtr<nsIRemoteService> mRemoteService;
2822 #endif
2824 ScopedXPCOMStartup* mScopedXPCom;
2825 ScopedAppData* mAppData;
2826 nsXREDirProvider mDirProvider;
2827 nsAutoCString mProfileName;
2828 nsAutoCString mDesktopStartupID;
2830 bool mStartOffline;
2831 bool mShuttingDown;
2832 #ifdef MOZ_ENABLE_XREMOTE
2833 bool mDisableRemote;
2834 #endif
2836 #if defined(MOZ_WIDGET_GTK)
2837 GdkDisplay* mGdkDisplay;
2838 #endif
2839 };
2841 /*
2842 * XRE_mainInit - Initial setup and command line parameter processing.
2843 * Main() will exit early if either return value != 0 or if aExitFlag is
2844 * true.
2845 */
2846 int
2847 XREMain::XRE_mainInit(bool* aExitFlag)
2848 {
2849 if (!aExitFlag)
2850 return 1;
2851 *aExitFlag = false;
2853 StartupTimeline::Record(StartupTimeline::MAIN);
2855 nsresult rv;
2856 ArgResult ar;
2858 #ifdef DEBUG
2859 if (PR_GetEnv("XRE_MAIN_BREAK"))
2860 NS_BREAK();
2861 #endif
2863 #ifdef USE_GLX_TEST
2864 // bug 639842 - it's very important to fire this process BEFORE we set up
2865 // error handling. indeed, this process is expected to be crashy, and we
2866 // don't want the user to see its crashes. That's the whole reason for
2867 // doing this in a separate process.
2868 //
2869 // This call will cause a fork and the fork will terminate itself separately
2870 // from the usual shutdown sequence
2871 fire_glxtest_process();
2872 #endif
2874 #if defined(XP_WIN) && defined(MOZ_METRO)
2875 // Don't remove this arg, we want to pass it on to nsUpdateDriver
2876 if (CheckArg("metro-update", false, nullptr, false) == ARG_FOUND ||
2877 XRE_GetWindowsEnvironment() == WindowsEnvironmentType_Metro) {
2878 // If we're doing a restart update that was initiated from metro land,
2879 // we'll be running desktop to handle the actual update. Request that
2880 // after the restart we launch into metro.
2881 SetLastWinRunType(AHE_IMMERSIVE);
2882 } else {
2883 SetLastWinRunType(AHE_DESKTOP);
2884 }
2885 #endif
2887 SetupErrorHandling(gArgv[0]);
2889 #ifdef CAIRO_HAS_DWRITE_FONT
2890 {
2891 // Bug 602792 - when DWriteCreateFactory is called the dwrite client dll
2892 // starts the FntCache service if it isn't already running (it's set
2893 // to manual startup by default in Windows 7 RTM). Subsequent DirectWrite
2894 // calls cause the IDWriteFactory object to communicate with the FntCache
2895 // service with a timeout; if there's no response after the timeout, the
2896 // DirectWrite client library will assume the service isn't around and do
2897 // manual font file I/O on _all_ system fonts. To avoid this, load the
2898 // dwrite library and create a factory as early as possible so that the
2899 // FntCache service is ready by the time it's needed.
2901 if (IsVistaOrLater()) {
2902 CreateThread(nullptr, 0, (LPTHREAD_START_ROUTINE)&InitDwriteBG,
2903 nullptr, 0, nullptr);
2904 }
2905 }
2906 #endif
2908 #ifdef XP_UNIX
2909 const char *home = PR_GetEnv("HOME");
2910 if (!home || !*home) {
2911 struct passwd *pw = getpwuid(geteuid());
2912 if (!pw || !pw->pw_dir) {
2913 Output(true, "Could not determine HOME directory");
2914 return 1;
2915 }
2916 SaveWordToEnv("HOME", nsDependentCString(pw->pw_dir));
2917 }
2918 #endif
2920 #ifdef MOZ_ACCESSIBILITY_ATK
2921 // Suppress atk-bridge init at startup, until mozilla accessibility is
2922 // initialized. This works after gnome 2.24.2.
2923 SaveToEnv("NO_AT_BRIDGE=1");
2924 #endif
2926 // Check for application.ini overrides
2927 const char* override = nullptr;
2928 ar = CheckArg("override", true, &override);
2929 if (ar == ARG_BAD) {
2930 Output(true, "Incorrect number of arguments passed to -override");
2931 return 1;
2932 }
2933 else if (ar == ARG_FOUND) {
2934 nsCOMPtr<nsIFile> overrideLF;
2935 rv = XRE_GetFileFromPath(override, getter_AddRefs(overrideLF));
2936 if (NS_FAILED(rv)) {
2937 Output(true, "Error: unrecognized override.ini path.\n");
2938 return 1;
2939 }
2941 rv = XRE_ParseAppData(overrideLF, mAppData);
2942 if (NS_FAILED(rv)) {
2943 Output(true, "Couldn't read override.ini");
2944 return 1;
2945 }
2946 }
2948 // Check sanity and correctness of app data.
2950 if (!mAppData->name) {
2951 Output(true, "Error: App:Name not specified in application.ini\n");
2952 return 1;
2953 }
2954 if (!mAppData->buildID) {
2955 Output(true, "Error: App:BuildID not specified in application.ini\n");
2956 return 1;
2957 }
2959 // XXX Originally ScopedLogging was here? Now it's in XRE_main above
2960 // XRE_mainInit.
2962 if (!mAppData->xreDirectory) {
2963 nsCOMPtr<nsIFile> lf;
2964 rv = XRE_GetBinaryPath(gArgv[0], getter_AddRefs(lf));
2965 if (NS_FAILED(rv))
2966 return 2;
2968 nsCOMPtr<nsIFile> greDir;
2969 rv = lf->GetParent(getter_AddRefs(greDir));
2970 if (NS_FAILED(rv))
2971 return 2;
2973 greDir.forget(&mAppData->xreDirectory);
2974 }
2976 if (!mAppData->directory) {
2977 NS_IF_ADDREF(mAppData->directory = mAppData->xreDirectory);
2978 }
2980 if (mAppData->size > offsetof(nsXREAppData, minVersion)) {
2981 if (!mAppData->minVersion) {
2982 Output(true, "Error: Gecko:MinVersion not specified in application.ini\n");
2983 return 1;
2984 }
2986 if (!mAppData->maxVersion) {
2987 // If no maxVersion is specified, we assume the app is only compatible
2988 // with the initial preview release. Do not increment this number ever!
2989 SetAllocatedString(mAppData->maxVersion, "1.*");
2990 }
2992 if (mozilla::Version(mAppData->minVersion) > gToolkitVersion ||
2993 mozilla::Version(mAppData->maxVersion) < gToolkitVersion) {
2994 Output(true, "Error: Platform version '%s' is not compatible with\n"
2995 "minVersion >= %s\nmaxVersion <= %s\n",
2996 gToolkitVersion,
2997 mAppData->minVersion, mAppData->maxVersion);
2998 return 1;
2999 }
3000 }
3002 rv = mDirProvider.Initialize(mAppData->directory, mAppData->xreDirectory);
3003 if (NS_FAILED(rv))
3004 return 1;
3006 #ifdef MOZ_CRASHREPORTER
3007 if (EnvHasValue("MOZ_CRASHREPORTER")) {
3008 mAppData->flags |= NS_XRE_ENABLE_CRASH_REPORTER;
3009 }
3011 if ((mAppData->flags & NS_XRE_ENABLE_CRASH_REPORTER) &&
3012 NS_SUCCEEDED(
3013 CrashReporter::SetExceptionHandler(mAppData->xreDirectory))) {
3014 CrashReporter::UpdateCrashEventsDir();
3015 if (mAppData->crashReporterURL)
3016 CrashReporter::SetServerURL(nsDependentCString(mAppData->crashReporterURL));
3018 // pass some basic info from the app data
3019 if (mAppData->vendor)
3020 CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("Vendor"),
3021 nsDependentCString(mAppData->vendor));
3022 if (mAppData->name)
3023 CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("ProductName"),
3024 nsDependentCString(mAppData->name));
3025 if (mAppData->ID)
3026 CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("ProductID"),
3027 nsDependentCString(mAppData->ID));
3028 if (mAppData->version)
3029 CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("Version"),
3030 nsDependentCString(mAppData->version));
3031 if (mAppData->buildID)
3032 CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("BuildID"),
3033 nsDependentCString(mAppData->buildID));
3035 nsDependentCString releaseChannel(NS_STRINGIFY(MOZ_UPDATE_CHANNEL));
3036 CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("ReleaseChannel"),
3037 releaseChannel);
3038 #ifdef MOZ_LINKER
3039 CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("CrashAddressLikelyWrong"),
3040 IsSignalHandlingBroken() ? NS_LITERAL_CSTRING("1")
3041 : NS_LITERAL_CSTRING("0"));
3042 #endif
3043 CrashReporter::SetRestartArgs(gArgc, gArgv);
3045 // annotate other data (user id etc)
3046 nsCOMPtr<nsIFile> userAppDataDir;
3047 if (NS_SUCCEEDED(mDirProvider.GetUserAppDataDirectory(
3048 getter_AddRefs(userAppDataDir)))) {
3049 CrashReporter::SetupExtraData(userAppDataDir,
3050 nsDependentCString(mAppData->buildID));
3052 // see if we have a crashreporter-override.ini in the application directory
3053 nsCOMPtr<nsIFile> overrideini;
3054 bool exists;
3055 if (NS_SUCCEEDED(mDirProvider.GetAppDir()->Clone(getter_AddRefs(overrideini))) &&
3056 NS_SUCCEEDED(overrideini->AppendNative(NS_LITERAL_CSTRING("crashreporter-override.ini"))) &&
3057 NS_SUCCEEDED(overrideini->Exists(&exists)) &&
3058 exists) {
3059 #ifdef XP_WIN
3060 nsAutoString overridePathW;
3061 overrideini->GetPath(overridePathW);
3062 NS_ConvertUTF16toUTF8 overridePath(overridePathW);
3063 #else
3064 nsAutoCString overridePath;
3065 overrideini->GetNativePath(overridePath);
3066 #endif
3068 SaveWordToEnv("MOZ_CRASHREPORTER_STRINGS_OVERRIDE", overridePath);
3069 }
3070 }
3071 }
3072 #endif
3074 #ifdef XP_MACOSX
3075 if (EnvHasValue("MOZ_LAUNCHED_CHILD")) {
3076 // This is needed, on relaunch, to force the OS to use the "Cocoa Dock
3077 // API". Otherwise the call to ReceiveNextEvent() below will make it
3078 // use the "Carbon Dock API". For more info see bmo bug 377166.
3079 EnsureUseCocoaDockAPI();
3081 // When the app relaunches, the original process exits. This causes
3082 // the dock tile to stop bouncing, lose the "running" triangle, and
3083 // if the tile does not permanently reside in the Dock, even disappear.
3084 // This can be confusing to the user, who is expecting the app to launch.
3085 // Calling ReceiveNextEvent without requesting any event is enough to
3086 // cause a dock tile for the child process to appear.
3087 const EventTypeSpec kFakeEventList[] = { { INT_MAX, INT_MAX } };
3088 EventRef event;
3089 ::ReceiveNextEvent(GetEventTypeCount(kFakeEventList), kFakeEventList,
3090 kEventDurationNoWait, false, &event);
3091 }
3093 if (CheckArg("foreground")) {
3094 // The original process communicates that it was in the foreground by
3095 // adding this argument. This new process, which is taking over for
3096 // the old one, should make itself the active application.
3097 ProcessSerialNumber psn;
3098 if (::GetCurrentProcess(&psn) == noErr)
3099 ::SetFrontProcess(&psn);
3100 }
3101 #endif
3103 SaveToEnv("MOZ_LAUNCHED_CHILD=");
3105 gRestartArgc = gArgc;
3106 gRestartArgv = (char**) malloc(sizeof(char*) * (gArgc + 1 + (override ? 2 : 0)));
3107 if (!gRestartArgv) {
3108 return 1;
3109 }
3111 int i;
3112 for (i = 0; i < gArgc; ++i) {
3113 gRestartArgv[i] = gArgv[i];
3114 }
3116 // Add the -override argument back (it is removed automatically be CheckArg) if there is one
3117 if (override) {
3118 gRestartArgv[gRestartArgc++] = const_cast<char*>("-override");
3119 gRestartArgv[gRestartArgc++] = const_cast<char*>(override);
3120 }
3122 gRestartArgv[gRestartArgc] = nullptr;
3125 if (EnvHasValue("MOZ_SAFE_MODE_RESTART")) {
3126 gSafeMode = true;
3127 // unset the env variable
3128 SaveToEnv("MOZ_SAFE_MODE_RESTART=");
3129 }
3131 ar = CheckArg("safe-mode", true);
3132 if (ar == ARG_BAD) {
3133 PR_fprintf(PR_STDERR, "Error: argument -safe-mode is invalid when argument -osint is specified\n");
3134 return 1;
3135 } else if (ar == ARG_FOUND) {
3136 gSafeMode = true;
3137 }
3139 #ifdef XP_WIN
3140 // If the shift key is pressed and the ctrl and / or alt keys are not pressed
3141 // during startup start in safe mode. GetKeyState returns a short and the high
3142 // order bit will be 1 if the key is pressed. By masking the returned short
3143 // with 0x8000 the result will be 0 if the key is not pressed and non-zero
3144 // otherwise.
3145 if (GetKeyState(VK_SHIFT) & 0x8000 &&
3146 !(GetKeyState(VK_CONTROL) & 0x8000) && !(GetKeyState(VK_MENU) & 0x8000)) {
3147 gSafeMode = true;
3148 }
3149 #endif
3151 #ifdef XP_MACOSX
3152 if (GetCurrentEventKeyModifiers() & optionKey)
3153 gSafeMode = true;
3154 #endif
3156 // In the Tor Browser, remoting is disabled by default unless -osint is used.
3157 bool allowRemote = (CheckArg("allow-remote") == ARG_FOUND);
3158 if (!allowRemote && (CheckArg("osint", false, nullptr, false) != ARG_FOUND))
3159 SaveToEnv("MOZ_NO_REMOTE=1");
3161 // Handle -no-remote and -new-instance command line arguments. Setup
3162 // the environment to better accommodate other components and various
3163 // restart scenarios.
3164 ar = CheckArg("no-remote", true);
3165 if (ar == ARG_BAD) {
3166 PR_fprintf(PR_STDERR, "Error: argument -no-remote is invalid when argument -osint is specified\n");
3167 return 1;
3168 } else if ((ar == ARG_FOUND) && allowRemote) {
3169 PR_fprintf(PR_STDERR, "Error: argument -no-remote is invalid when argument -allow-remote is specified\n");
3170 return 1;
3171 }
3173 ar = CheckArg("new-instance", true);
3174 if (ar == ARG_BAD) {
3175 PR_fprintf(PR_STDERR, "Error: argument -new-instance is invalid when argument -osint is specified\n");
3176 return 1;
3177 } else if (ar == ARG_FOUND) {
3178 SaveToEnv("MOZ_NEW_INSTANCE=1");
3179 }
3181 // Handle -help and -version command line arguments.
3182 // They should return quickly, so we deal with them here.
3183 if (CheckArg("h") || CheckArg("help") || CheckArg("?")) {
3184 DumpHelp();
3185 *aExitFlag = true;
3186 return 0;
3187 }
3189 if (CheckArg("v") || CheckArg("version")) {
3190 DumpVersion();
3191 *aExitFlag = true;
3192 return 0;
3193 }
3195 #ifdef NS_TRACE_MALLOC
3196 gArgc = NS_TraceMallocStartupArgs(gArgc, gArgv);
3197 #endif
3199 rv = XRE_InitCommandLine(gArgc, gArgv);
3200 NS_ENSURE_SUCCESS(rv, 1);
3202 // Check for -register, which registers chrome and then exits immediately.
3203 ar = CheckArg("register", true);
3204 if (ar == ARG_BAD) {
3205 PR_fprintf(PR_STDERR, "Error: argument -register is invalid when argument -osint is specified\n");
3206 return 1;
3207 } else if (ar == ARG_FOUND) {
3208 ScopedXPCOMStartup xpcom;
3209 rv = xpcom.Initialize();
3210 NS_ENSURE_SUCCESS(rv, 1);
3211 {
3212 nsCOMPtr<nsIChromeRegistry> chromeReg =
3213 mozilla::services::GetChromeRegistryService();
3214 NS_ENSURE_TRUE(chromeReg, 1);
3216 chromeReg->CheckForNewChrome();
3217 }
3218 *aExitFlag = true;
3219 return 0;
3220 }
3222 if (PR_GetEnv("MOZ_RUN_GTEST")) {
3223 int result;
3224 // RunGTest will only be set if we're in xul-unit
3225 if (mozilla::RunGTest) {
3226 result = mozilla::RunGTest();
3227 } else {
3228 result = 1;
3229 printf("TEST-UNEXPECTED-FAIL | gtest | Not compiled with enable-tests\n");
3230 }
3231 *aExitFlag = true;
3232 return result;
3233 }
3235 return 0;
3236 }
3238 #ifdef MOZ_CRASHREPORTER
3239 #ifdef XP_WIN
3240 /**
3241 * Uses WMI to read some manufacturer information that may be useful for
3242 * diagnosing hardware-specific crashes. This function is best-effort; failures
3243 * shouldn't burden the caller. COM must be initialized before calling.
3244 */
3245 static void AnnotateSystemManufacturer()
3246 {
3247 nsRefPtr<IWbemLocator> locator;
3249 HRESULT hr = CoCreateInstance(CLSID_WbemLocator, nullptr, CLSCTX_INPROC_SERVER,
3250 IID_IWbemLocator, getter_AddRefs(locator));
3252 if (FAILED(hr)) {
3253 return;
3254 }
3256 nsRefPtr<IWbemServices> services;
3258 hr = locator->ConnectServer(_bstr_t(L"ROOT\\CIMV2"), nullptr, nullptr, nullptr,
3259 0, nullptr, nullptr, getter_AddRefs(services));
3261 if (FAILED(hr)) {
3262 return;
3263 }
3265 hr = CoSetProxyBlanket(services, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, nullptr,
3266 RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE,
3267 nullptr, EOAC_NONE);
3269 if (FAILED(hr)) {
3270 return;
3271 }
3273 nsRefPtr<IEnumWbemClassObject> enumerator;
3275 hr = services->ExecQuery(_bstr_t(L"WQL"), _bstr_t(L"SELECT * FROM Win32_BIOS"),
3276 WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
3277 nullptr, getter_AddRefs(enumerator));
3279 if (FAILED(hr) || !enumerator) {
3280 return;
3281 }
3283 nsRefPtr<IWbemClassObject> classObject;
3284 ULONG results;
3286 hr = enumerator->Next(WBEM_INFINITE, 1, getter_AddRefs(classObject), &results);
3288 if (FAILED(hr) || results == 0) {
3289 return;
3290 }
3292 VARIANT value;
3293 VariantInit(&value);
3295 hr = classObject->Get(L"Manufacturer", 0, &value, 0, 0);
3297 if (SUCCEEDED(hr) && V_VT(&value) == VT_BSTR) {
3298 CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("BIOS_Manufacturer"),
3299 NS_ConvertUTF16toUTF8(V_BSTR(&value)));
3300 }
3302 VariantClear(&value);
3303 }
3305 static void PR_CALLBACK AnnotateSystemManufacturer_ThreadStart(void*)
3306 {
3307 HRESULT hr = CoInitialize(nullptr);
3309 if (FAILED(hr)) {
3310 return;
3311 }
3313 AnnotateSystemManufacturer();
3315 CoUninitialize();
3316 }
3317 #endif
3318 #endif
3320 namespace mozilla {
3321 ShutdownChecksMode gShutdownChecks = SCM_NOTHING;
3322 }
3324 static void SetShutdownChecks() {
3325 // Set default first. On debug builds we crash. On nightly and local
3326 // builds we record. Nightlies will then send the info via telemetry,
3327 // but it is usefull to have the data in about:telemetry in local builds
3328 // too.
3330 #ifdef DEBUG
3331 gShutdownChecks = SCM_CRASH;
3332 #else
3333 const char* releaseChannel = NS_STRINGIFY(MOZ_UPDATE_CHANNEL);
3334 if (strcmp(releaseChannel, "nightly") == 0 ||
3335 strcmp(releaseChannel, "default") == 0) {
3336 gShutdownChecks = SCM_RECORD;
3337 } else {
3338 gShutdownChecks = SCM_NOTHING;
3339 }
3340 #endif
3342 // We let an environment variable override the default so that addons
3343 // authors can use it for debugging shutdown with released firefox versions.
3344 const char* mozShutdownChecksEnv = PR_GetEnv("MOZ_SHUTDOWN_CHECKS");
3345 if (mozShutdownChecksEnv) {
3346 if (strcmp(mozShutdownChecksEnv, "crash") == 0) {
3347 gShutdownChecks = SCM_CRASH;
3348 } else if (strcmp(mozShutdownChecksEnv, "record") == 0) {
3349 gShutdownChecks = SCM_RECORD;
3350 } else if (strcmp(mozShutdownChecksEnv, "nothing") == 0) {
3351 gShutdownChecks = SCM_NOTHING;
3352 }
3353 }
3355 }
3357 /*
3358 * XRE_mainStartup - Initializes the profile and various other services.
3359 * Main() will exit early if either return value != 0 or if aExitFlag is
3360 * true.
3361 */
3362 int
3363 XREMain::XRE_mainStartup(bool* aExitFlag)
3364 {
3365 nsresult rv;
3367 if (!aExitFlag)
3368 return 1;
3369 *aExitFlag = false;
3371 SetShutdownChecks();
3374 // Enable Telemetry IO Reporting on DEBUG, nightly and local builds
3375 #ifdef DEBUG
3376 mozilla::Telemetry::InitIOReporting(gAppData->xreDirectory);
3377 #else
3378 {
3379 const char* releaseChannel = NS_STRINGIFY(MOZ_UPDATE_CHANNEL);
3380 if (strcmp(releaseChannel, "nightly") == 0 ||
3381 strcmp(releaseChannel, "default") == 0) {
3382 mozilla::Telemetry::InitIOReporting(gAppData->xreDirectory);
3383 }
3384 }
3385 #endif /* DEBUG */
3387 #if defined(MOZ_WIDGET_GTK) || defined(MOZ_ENABLE_XREMOTE)
3388 // Stash DESKTOP_STARTUP_ID in malloc'ed memory because gtk_init will clear it.
3389 #define HAVE_DESKTOP_STARTUP_ID
3390 const char* desktopStartupIDEnv = PR_GetEnv("DESKTOP_STARTUP_ID");
3391 if (desktopStartupIDEnv) {
3392 mDesktopStartupID.Assign(desktopStartupIDEnv);
3393 }
3394 #endif
3396 #if defined(MOZ_WIDGET_QT)
3397 nsQAppInstance::AddRef(gArgc, gArgv, true);
3399 QStringList nonQtArguments = qApp->arguments();
3400 gQtOnlyArgc = 1;
3401 gQtOnlyArgv = (char**) malloc(sizeof(char*)
3402 * (gRestartArgc - nonQtArguments.size() + 2));
3404 // copy binary path
3405 gQtOnlyArgv[0] = gRestartArgv[0];
3407 for (int i = 1; i < gRestartArgc; ++i) {
3408 if (!nonQtArguments.contains(gRestartArgv[i])) {
3409 // copy arguments used by Qt for later
3410 gQtOnlyArgv[gQtOnlyArgc++] = gRestartArgv[i];
3411 }
3412 }
3413 gQtOnlyArgv[gQtOnlyArgc] = nullptr;
3414 #endif
3415 #if defined(MOZ_WIDGET_GTK)
3416 // setup for private colormap. Ideally we'd like to do this
3417 // in nsAppShell::Create, but we need to get in before gtk
3418 // has been initialized to make sure everything is running
3419 // consistently.
3420 #if (MOZ_WIDGET_GTK == 2)
3421 if (CheckArg("install"))
3422 gdk_rgb_set_install(TRUE);
3423 #endif
3425 // Set program name to the one defined in application.ini.
3426 {
3427 nsAutoCString program(gAppData->name);
3428 ToLowerCase(program);
3429 g_set_prgname(program.get());
3430 }
3432 // Initialize GTK here for splash.
3434 // Open the display ourselves instead of using gtk_init, so that we can
3435 // close it without fear that one day gtk might clean up the display it
3436 // opens.
3437 if (!gtk_parse_args(&gArgc, &gArgv))
3438 return 1;
3440 // display_name is owned by gdk.
3441 const char *display_name = gdk_get_display_arg_name();
3442 if (display_name) {
3443 SaveWordToEnv("DISPLAY", nsDependentCString(display_name));
3444 } else {
3445 display_name = PR_GetEnv("DISPLAY");
3446 if (!display_name) {
3447 PR_fprintf(PR_STDERR, "Error: no display specified\n");
3448 return 1;
3449 }
3450 }
3451 #endif /* MOZ_WIDGET_GTK2 */
3453 #ifdef MOZ_ENABLE_XREMOTE
3454 // handle -remote now that xpcom is fired up
3455 bool newInstance;
3456 {
3457 char *e = PR_GetEnv("MOZ_NO_REMOTE");
3458 mDisableRemote = (e && *e);
3459 if (mDisableRemote) {
3460 newInstance = true;
3461 } else {
3462 e = PR_GetEnv("MOZ_NEW_INSTANCE");
3463 newInstance = (e && *e);
3464 }
3465 }
3467 const char* xremotearg;
3468 ArgResult ar = CheckArg("remote", true, &xremotearg);
3469 if (ar == ARG_BAD) {
3470 PR_fprintf(PR_STDERR, "Error: -remote requires an argument\n");
3471 return 1;
3472 }
3473 const char* desktopStartupIDPtr =
3474 mDesktopStartupID.IsEmpty() ? nullptr : mDesktopStartupID.get();
3475 if (ar) {
3476 *aExitFlag = true;
3477 return HandleRemoteArgument(xremotearg, desktopStartupIDPtr);
3478 }
3480 if (!newInstance) {
3481 // Try to remote the entire command line. If this fails, start up normally.
3482 RemoteResult rr = RemoteCommandLine(desktopStartupIDPtr);
3483 if (rr == REMOTE_FOUND) {
3484 *aExitFlag = true;
3485 return 0;
3486 }
3487 else if (rr == REMOTE_ARG_BAD)
3488 return 1;
3489 }
3490 #endif
3491 #ifdef MOZ_X11
3492 // Init X11 in thread-safe mode. Must be called prior to the first call to XOpenDisplay
3493 // (called inside gdk_display_open). This is a requirement for off main tread compositing.
3494 // This is done only on X11 platforms if the environment variable MOZ_USE_OMTC is set so
3495 // as to avoid overhead when omtc is not used.
3496 //
3497 // On nightly builds, we call this by default to enable OMTC for Electrolysis testing. On
3498 // aurora, beta, and release builds, there is a small tpaint regression from enabling this
3499 // call, so it sits behind an environment variable.
3500 //
3501 // An environment variable is used instead of a pref on X11 platforms because we start having
3502 // access to prefs long after the first call to XOpenDisplay which is hard to change due to
3503 // interdependencies in the initialization.
3504 # ifndef NIGHTLY_BUILD
3505 if (PR_GetEnv("MOZ_USE_OMTC") ||
3506 PR_GetEnv("MOZ_OMTC_ENABLED"))
3507 # endif
3508 {
3509 XInitThreads();
3510 }
3511 #endif
3512 #if defined(MOZ_WIDGET_GTK)
3513 mGdkDisplay = gdk_display_open(display_name);
3514 if (!mGdkDisplay) {
3515 PR_fprintf(PR_STDERR, "Error: cannot open display: %s\n", display_name);
3516 return 1;
3517 }
3518 gdk_display_manager_set_default_display (gdk_display_manager_get(),
3519 mGdkDisplay);
3521 // g_set_application_name () is only defined in glib2.2 and higher.
3522 _g_set_application_name_fn _g_set_application_name =
3523 (_g_set_application_name_fn)FindFunction("g_set_application_name");
3524 if (_g_set_application_name) {
3525 _g_set_application_name(mAppData->name);
3526 }
3527 _gtk_window_set_auto_startup_notification_fn _gtk_window_set_auto_startup_notification =
3528 (_gtk_window_set_auto_startup_notification_fn)FindFunction("gtk_window_set_auto_startup_notification");
3529 if (_gtk_window_set_auto_startup_notification) {
3530 _gtk_window_set_auto_startup_notification(false);
3531 }
3533 #if (MOZ_WIDGET_GTK == 2)
3534 gtk_widget_set_default_colormap(gdk_rgb_get_colormap());
3535 #endif /* (MOZ_WIDGET_GTK == 2) */
3536 #endif /* defined(MOZ_WIDGET_GTK) */
3537 #ifdef MOZ_X11
3538 // Do this after initializing GDK, or GDK will install its own handler.
3539 InstallX11ErrorHandler();
3540 #endif
3542 // Call the code to install our handler
3543 #ifdef MOZ_JPROF
3544 setupProfilingStuff();
3545 #endif
3547 rv = NS_CreateNativeAppSupport(getter_AddRefs(mNativeApp));
3548 if (NS_FAILED(rv))
3549 return 1;
3551 bool canRun = false;
3552 rv = mNativeApp->Start(&canRun);
3553 if (NS_FAILED(rv) || !canRun) {
3554 return 1;
3555 }
3557 #if defined(HAVE_DESKTOP_STARTUP_ID) && defined(MOZ_WIDGET_GTK)
3558 // DESKTOP_STARTUP_ID is cleared now,
3559 // we recover it in case we need a restart.
3560 if (!mDesktopStartupID.IsEmpty()) {
3561 nsAutoCString desktopStartupEnv;
3562 desktopStartupEnv.AssignLiteral("DESKTOP_STARTUP_ID=");
3563 desktopStartupEnv.Append(mDesktopStartupID);
3564 // Leak it with extreme prejudice!
3565 PR_SetEnv(ToNewCString(desktopStartupEnv));
3566 }
3567 #endif
3569 #if defined(USE_MOZ_UPDATER)
3570 // Check for and process any available updates
3571 nsCOMPtr<nsIFile> updRoot;
3572 bool persistent;
3573 rv = mDirProvider.GetFile(XRE_UPDATE_ROOT_DIR, &persistent,
3574 getter_AddRefs(updRoot));
3575 // XRE_UPDATE_ROOT_DIR may fail. Fallback to appDir if failed
3576 if (NS_FAILED(rv))
3577 updRoot = mDirProvider.GetAppDir();
3579 // If the MOZ_PROCESS_UPDATES environment variable already exists, then
3580 // we are being called from the callback application.
3581 if (EnvHasValue("MOZ_PROCESS_UPDATES")) {
3582 // If the caller has asked us to log our arguments, do so. This is used
3583 // to make sure that the maintenance service successfully launches the
3584 // callback application.
3585 const char *logFile = nullptr;
3586 if (ARG_FOUND == CheckArg("dump-args", false, &logFile)) {
3587 FILE* logFP = fopen(logFile, "wb");
3588 if (logFP) {
3589 for (int i = 1; i < gRestartArgc; ++i) {
3590 fprintf(logFP, "%s\n", gRestartArgv[i]);
3591 }
3592 fclose(logFP);
3593 }
3594 }
3595 *aExitFlag = true;
3596 return 0;
3597 }
3599 // Support for processing an update and exiting. The MOZ_PROCESS_UPDATES
3600 // environment variable will be part of the updater's environment and the
3601 // application that is relaunched by the updater. When the application is
3602 // relaunched by the updater it will be removed below and the application
3603 // will exit.
3604 if (CheckArg("process-updates")) {
3605 SaveToEnv("MOZ_PROCESS_UPDATES=1");
3606 }
3607 nsCOMPtr<nsIFile> exeFile, exeDir;
3608 rv = mDirProvider.GetFile(XRE_EXECUTABLE_FILE, &persistent,
3609 getter_AddRefs(exeFile));
3610 NS_ENSURE_SUCCESS(rv, 1);
3611 rv = exeFile->GetParent(getter_AddRefs(exeDir));
3612 NS_ENSURE_SUCCESS(rv, 1);
3613 #ifdef TOR_BROWSER_UPDATE
3614 nsAutoCString compatVersion(TOR_BROWSER_VERSION);
3615 #endif
3616 ProcessUpdates(mDirProvider.GetGREDir(),
3617 exeDir,
3618 updRoot,
3619 gRestartArgc,
3620 gRestartArgv,
3621 #ifdef TOR_BROWSER_UPDATE
3622 compatVersion.get()
3623 #else
3624 mAppData->version
3625 #endif
3626 );
3627 if (EnvHasValue("MOZ_PROCESS_UPDATES")) {
3628 SaveToEnv("MOZ_PROCESS_UPDATES=");
3629 *aExitFlag = true;
3630 return 0;
3631 }
3632 #if defined(XP_WIN) && defined(MOZ_METRO)
3633 if (CheckArg("metro-update", false) == ARG_FOUND) {
3634 *aExitFlag = true;
3635 return 0;
3636 }
3637 #endif
3638 #endif
3640 rv = NS_NewToolkitProfileService(getter_AddRefs(mProfileSvc));
3641 if (rv == NS_ERROR_FILE_ACCESS_DENIED) {
3642 PR_fprintf(PR_STDERR, "Error: Access was denied while trying to open files in " \
3643 "your profile directory.\n");
3644 }
3645 if (NS_FAILED(rv)) {
3646 // We failed to choose or create profile - notify user and quit
3647 ProfileMissingDialog(mNativeApp);
3648 return 1;
3649 }
3651 rv = SelectProfile(getter_AddRefs(mProfileLock), mProfileSvc, mNativeApp, &mStartOffline,
3652 &mProfileName);
3653 if (rv == NS_ERROR_LAUNCHED_CHILD_PROCESS ||
3654 rv == NS_ERROR_ABORT) {
3655 *aExitFlag = true;
3656 return 0;
3657 }
3659 if (NS_FAILED(rv)) {
3660 // We failed to choose or create profile - notify user and quit
3661 ProfileMissingDialog(mNativeApp);
3662 return 1;
3663 }
3664 gProfileLock = mProfileLock;
3666 rv = mProfileLock->GetDirectory(getter_AddRefs(mProfD));
3667 NS_ENSURE_SUCCESS(rv, 1);
3669 rv = mProfileLock->GetLocalDirectory(getter_AddRefs(mProfLD));
3670 NS_ENSURE_SUCCESS(rv, 1);
3672 rv = mDirProvider.SetProfile(mProfD, mProfLD);
3673 NS_ENSURE_SUCCESS(rv, 1);
3675 //////////////////////// NOW WE HAVE A PROFILE ////////////////////////
3677 mozilla::Telemetry::SetProfileDir(mProfD);
3679 #ifdef MOZ_CRASHREPORTER
3680 if (mAppData->flags & NS_XRE_ENABLE_CRASH_REPORTER)
3681 MakeOrSetMinidumpPath(mProfD);
3683 CrashReporter::UpdateCrashEventsDir();
3684 #endif
3686 nsAutoCString version;
3687 BuildVersion(version);
3689 #ifdef TARGET_OS_ABI
3690 NS_NAMED_LITERAL_CSTRING(osABI, TARGET_OS_ABI);
3691 #else
3692 // No TARGET_XPCOM_ABI, but at least the OS is known
3693 NS_NAMED_LITERAL_CSTRING(osABI, OS_TARGET "_UNKNOWN");
3694 #endif
3696 // Check for version compatibility with the last version of the app this
3697 // profile was started with. The format of the version stamp is defined
3698 // by the BuildVersion function.
3699 // Also check to see if something has happened to invalidate our
3700 // fastload caches, like an extension upgrade or installation.
3702 // If we see .purgecaches, that means someone did a make.
3703 // Re-register components to catch potential changes.
3704 nsCOMPtr<nsIFile> flagFile;
3706 rv = NS_ERROR_FILE_NOT_FOUND;
3707 nsCOMPtr<nsIFile> fFlagFile;
3708 if (mAppData->directory) {
3709 rv = mAppData->directory->Clone(getter_AddRefs(fFlagFile));
3710 }
3711 flagFile = do_QueryInterface(fFlagFile);
3712 if (flagFile) {
3713 flagFile->AppendNative(FILE_INVALIDATE_CACHES);
3714 }
3716 bool cachesOK;
3717 bool versionOK = CheckCompatibility(mProfD, version, osABI,
3718 mDirProvider.GetGREDir(),
3719 mAppData->directory, flagFile,
3720 &cachesOK);
3721 if (CheckArg("purgecaches")) {
3722 cachesOK = false;
3723 }
3724 if (PR_GetEnv("MOZ_PURGE_CACHES")) {
3725 cachesOK = false;
3726 }
3728 // Every time a profile is loaded by a build with a different version,
3729 // it updates the compatibility.ini file saying what version last wrote
3730 // the fastload caches. On subsequent launches if the version matches,
3731 // there is no need for re-registration. If the user loads the same
3732 // profile in different builds the component registry must be
3733 // re-generated to prevent mysterious component loading failures.
3734 //
3735 bool startupCacheValid = true;
3736 if (gSafeMode) {
3737 startupCacheValid = RemoveComponentRegistries(mProfD, mProfLD, false);
3738 WriteVersion(mProfD, NS_LITERAL_CSTRING("Safe Mode"), osABI,
3739 mDirProvider.GetGREDir(), mAppData->directory, !startupCacheValid);
3740 }
3741 else if (versionOK) {
3742 if (!cachesOK) {
3743 // Remove caches, forcing component re-registration.
3744 // The new list of additional components directories is derived from
3745 // information in "extensions.ini".
3746 startupCacheValid = RemoveComponentRegistries(mProfD, mProfLD, false);
3748 // Rewrite compatibility.ini to remove the flag
3749 WriteVersion(mProfD, version, osABI,
3750 mDirProvider.GetGREDir(), mAppData->directory, !startupCacheValid);
3751 }
3752 // Nothing need be done for the normal startup case.
3753 }
3754 else {
3755 // Remove caches, forcing component re-registration
3756 // with the default set of components (this disables any potentially
3757 // troublesome incompatible XPCOM components).
3758 startupCacheValid = RemoveComponentRegistries(mProfD, mProfLD, true);
3760 // Write out version
3761 WriteVersion(mProfD, version, osABI,
3762 mDirProvider.GetGREDir(), mAppData->directory, !startupCacheValid);
3763 }
3765 if (!startupCacheValid)
3766 StartupCache::IgnoreDiskCache();
3768 if (flagFile) {
3769 flagFile->Remove(true);
3770 }
3772 return 0;
3773 }
3775 /*
3776 * XRE_mainRun - Command line startup, profile migration, and
3777 * the calling of appStartup->Run().
3778 */
3779 nsresult
3780 XREMain::XRE_mainRun()
3781 {
3782 nsresult rv = NS_OK;
3783 NS_ASSERTION(mScopedXPCom, "Scoped xpcom not initialized.");
3785 #ifdef NS_FUNCTION_TIMER
3786 // initialize some common services, so we don't pay the cost for these at odd times later on;
3787 // SetWindowCreator -> ChromeRegistry -> IOService -> SocketTransportService -> (nspr wspm init), Prefs
3788 {
3789 nsCOMPtr<nsISupports> comp;
3791 comp = do_GetService("@mozilla.org/preferences-service;1");
3793 comp = do_GetService("@mozilla.org/network/socket-transport-service;1");
3795 comp = do_GetService("@mozilla.org/network/dns-service;1");
3797 comp = do_GetService("@mozilla.org/network/io-service;1");
3799 comp = do_GetService("@mozilla.org/chrome/chrome-registry;1");
3801 comp = do_GetService("@mozilla.org/focus-event-suppressor-service;1");
3802 }
3803 #endif
3805 rv = mScopedXPCom->SetWindowCreator(mNativeApp);
3806 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
3808 #ifdef MOZ_CRASHREPORTER
3809 // tell the crash reporter to also send the release channel
3810 nsCOMPtr<nsIPrefService> prefs = do_GetService("@mozilla.org/preferences-service;1", &rv);
3811 if (NS_SUCCEEDED(rv)) {
3812 nsCOMPtr<nsIPrefBranch> defaultPrefBranch;
3813 rv = prefs->GetDefaultBranch(nullptr, getter_AddRefs(defaultPrefBranch));
3815 if (NS_SUCCEEDED(rv)) {
3816 nsXPIDLCString sval;
3817 rv = defaultPrefBranch->GetCharPref("app.update.channel", getter_Copies(sval));
3818 if (NS_SUCCEEDED(rv)) {
3819 CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("ReleaseChannel"),
3820 sval);
3821 }
3822 }
3823 }
3824 // Needs to be set after xpcom initialization.
3825 CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("FramePoisonBase"),
3826 nsPrintfCString("%.16llx", uint64_t(gMozillaPoisonBase)));
3827 CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("FramePoisonSize"),
3828 nsPrintfCString("%lu", uint32_t(gMozillaPoisonSize)));
3830 #ifdef XP_WIN
3831 PR_CreateThread(PR_USER_THREAD, AnnotateSystemManufacturer_ThreadStart, 0,
3832 PR_PRIORITY_LOW, PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD, 0);
3833 #endif
3835 #endif
3837 if (mStartOffline) {
3838 nsCOMPtr<nsIIOService2> io (do_GetService("@mozilla.org/network/io-service;1"));
3839 NS_ENSURE_TRUE(io, NS_ERROR_FAILURE);
3840 io->SetManageOfflineStatus(false);
3841 io->SetOffline(true);
3842 }
3844 {
3845 nsCOMPtr<nsIObserver> startupNotifier
3846 (do_CreateInstance(NS_APPSTARTUPNOTIFIER_CONTRACTID, &rv));
3847 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
3849 startupNotifier->Observe(nullptr, APPSTARTUP_TOPIC, nullptr);
3850 }
3852 nsCOMPtr<nsIAppStartup> appStartup
3853 (do_GetService(NS_APPSTARTUP_CONTRACTID));
3854 NS_ENSURE_TRUE(appStartup, NS_ERROR_FAILURE);
3856 if (gDoMigration) {
3857 nsCOMPtr<nsIFile> file;
3858 mDirProvider.GetAppDir()->Clone(getter_AddRefs(file));
3859 file->AppendNative(NS_LITERAL_CSTRING("override.ini"));
3860 nsINIParser parser;
3861 nsresult rv = parser.Init(file);
3862 if (NS_SUCCEEDED(rv)) {
3863 nsAutoCString buf;
3864 rv = parser.GetString("XRE", "EnableProfileMigrator", buf);
3865 if (NS_SUCCEEDED(rv)) {
3866 if (buf[0] == '0' || buf[0] == 'f' || buf[0] == 'F') {
3867 gDoMigration = false;
3868 }
3869 }
3870 }
3871 }
3873 {
3874 nsCOMPtr<nsIToolkitProfile> selectedProfile;
3875 if (gDoProfileReset) {
3876 // At this point we can be sure that profile reset is happening on the default profile.
3877 rv = mProfileSvc->GetSelectedProfile(getter_AddRefs(selectedProfile));
3878 if (NS_FAILED(rv)) {
3879 gDoProfileReset = false;
3880 return NS_ERROR_FAILURE;
3881 }
3882 }
3884 // Profile Migration
3885 if (mAppData->flags & NS_XRE_ENABLE_PROFILE_MIGRATOR && gDoMigration) {
3886 gDoMigration = false;
3887 nsCOMPtr<nsIProfileMigrator> pm(do_CreateInstance(NS_PROFILEMIGRATOR_CONTRACTID));
3888 if (pm) {
3889 nsAutoCString aKey;
3890 if (gDoProfileReset) {
3891 // Automatically migrate from the current application if we just
3892 // reset the profile.
3893 aKey = MOZ_APP_NAME;
3894 }
3895 pm->Migrate(&mDirProvider, aKey);
3896 }
3897 }
3899 if (gDoProfileReset) {
3900 nsresult backupCreated = ProfileResetCleanup(selectedProfile);
3901 if (NS_FAILED(backupCreated)) NS_WARNING("Could not cleanup the profile that was reset");
3903 // Set the new profile as the default after we're done cleaning up the old default.
3904 rv = SetCurrentProfileAsDefault(mProfileSvc, mProfD);
3905 if (NS_FAILED(rv)) NS_WARNING("Could not set current profile as the default");
3906 }
3907 }
3909 mDirProvider.DoStartup();
3911 #ifdef MOZ_CRASHREPORTER
3912 nsCString userAgentLocale;
3913 if (NS_SUCCEEDED(Preferences::GetCString("general.useragent.locale", &userAgentLocale))) {
3914 CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("useragent_locale"), userAgentLocale);
3915 }
3916 #endif
3918 appStartup->GetShuttingDown(&mShuttingDown);
3920 nsCOMPtr<nsICommandLineRunner> cmdLine;
3922 nsCOMPtr<nsIFile> workingDir;
3923 rv = NS_GetSpecialDirectory(NS_OS_CURRENT_WORKING_DIR, getter_AddRefs(workingDir));
3924 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
3926 if (!mShuttingDown) {
3927 cmdLine = do_CreateInstance("@mozilla.org/toolkit/command-line;1");
3928 NS_ENSURE_TRUE(cmdLine, NS_ERROR_FAILURE);
3930 rv = cmdLine->Init(gArgc, gArgv, workingDir,
3931 nsICommandLine::STATE_INITIAL_LAUNCH);
3932 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
3934 /* Special-case services that need early access to the command
3935 line. */
3936 nsCOMPtr<nsIObserverService> obsService =
3937 mozilla::services::GetObserverService();
3938 if (obsService) {
3939 obsService->NotifyObservers(cmdLine, "command-line-startup", nullptr);
3940 }
3941 }
3943 SaveStateForAppInitiatedRestart();
3945 // clear out any environment variables which may have been set
3946 // during the relaunch process now that we know we won't be relaunching.
3947 SaveToEnv("XRE_PROFILE_PATH=");
3948 SaveToEnv("XRE_PROFILE_LOCAL_PATH=");
3949 SaveToEnv("XRE_PROFILE_NAME=");
3950 SaveToEnv("XRE_START_OFFLINE=");
3951 SaveToEnv("NO_EM_RESTART=");
3952 SaveToEnv("XUL_APP_FILE=");
3953 SaveToEnv("XRE_BINARY_PATH=");
3955 if (!mShuttingDown) {
3956 rv = appStartup->CreateHiddenWindow();
3957 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
3959 #if defined(HAVE_DESKTOP_STARTUP_ID) && defined(MOZ_WIDGET_GTK)
3960 nsGTKToolkit* toolkit = nsGTKToolkit::GetToolkit();
3961 if (toolkit && !mDesktopStartupID.IsEmpty()) {
3962 toolkit->SetDesktopStartupID(mDesktopStartupID);
3963 }
3964 // Clear the environment variable so it won't be inherited by
3965 // child processes and confuse things.
3966 g_unsetenv ("DESKTOP_STARTUP_ID");
3967 #endif
3969 #ifdef XP_MACOSX
3970 // Set up ability to respond to system (Apple) events. This must be
3971 // done before setting up the command line service.
3972 SetupMacApplicationDelegate();
3974 // we re-initialize the command-line service and do appleevents munging
3975 // after we are sure that we're not restarting
3976 cmdLine = do_CreateInstance("@mozilla.org/toolkit/command-line;1");
3977 NS_ENSURE_TRUE(cmdLine, NS_ERROR_FAILURE);
3979 CommandLineServiceMac::SetupMacCommandLine(gArgc, gArgv, false);
3981 rv = cmdLine->Init(gArgc, gArgv,
3982 workingDir, nsICommandLine::STATE_INITIAL_LAUNCH);
3983 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
3984 #endif
3986 nsCOMPtr<nsIObserverService> obsService =
3987 mozilla::services::GetObserverService();
3988 if (obsService)
3989 obsService->NotifyObservers(nullptr, "final-ui-startup", nullptr);
3991 (void)appStartup->DoneStartingUp();
3992 appStartup->GetShuttingDown(&mShuttingDown);
3993 }
3995 if (!mShuttingDown) {
3996 rv = cmdLine->Run();
3997 NS_ENSURE_SUCCESS_LOG(rv, NS_ERROR_FAILURE);
3999 appStartup->GetShuttingDown(&mShuttingDown);
4000 }
4002 if (!mShuttingDown) {
4003 #ifdef MOZ_ENABLE_XREMOTE
4004 // if we have X remote support, start listening for requests on the
4005 // proxy window.
4006 if (!mDisableRemote)
4007 mRemoteService = do_GetService("@mozilla.org/toolkit/remote-service;1");
4008 if (mRemoteService)
4009 mRemoteService->Startup(mAppData->name, mProfileName.get());
4010 #endif /* MOZ_ENABLE_XREMOTE */
4012 mNativeApp->Enable();
4013 }
4015 #ifdef MOZ_INSTRUMENT_EVENT_LOOP
4016 if (PR_GetEnv("MOZ_INSTRUMENT_EVENT_LOOP") || profiler_is_active()) {
4017 bool logToConsole = !!PR_GetEnv("MOZ_INSTRUMENT_EVENT_LOOP");
4018 mozilla::InitEventTracing(logToConsole);
4019 }
4020 #endif /* MOZ_INSTRUMENT_EVENT_LOOP */
4022 {
4023 rv = appStartup->Run();
4024 if (NS_FAILED(rv)) {
4025 NS_ERROR("failed to run appstartup");
4026 gLogConsoleErrors = true;
4027 }
4028 }
4030 return rv;
4031 }
4033 /*
4034 * XRE_main - A class based main entry point used by most platforms.
4035 */
4036 int
4037 XREMain::XRE_main(int argc, char* argv[], const nsXREAppData* aAppData)
4038 {
4039 char aLocal;
4040 GeckoProfilerInitRAII profilerGuard(&aLocal);
4041 PROFILER_LABEL("Startup", "XRE_Main");
4043 mozilla::IOInterposerInit ioInterposerGuard;
4045 nsresult rv = NS_OK;
4047 gArgc = argc;
4048 gArgv = argv;
4050 NS_ENSURE_TRUE(aAppData, 2);
4052 mAppData = new ScopedAppData(aAppData);
4053 if (!mAppData)
4054 return 1;
4055 // used throughout this file
4056 gAppData = mAppData;
4058 ScopedLogging log;
4060 #if defined(MOZ_WIDGET_GTK)
4061 #if defined(MOZ_MEMORY) || defined(__FreeBSD__) || defined(__NetBSD__)
4062 // Disable the slice allocator, since jemalloc already uses similar layout
4063 // algorithms, and using a sub-allocator tends to increase fragmentation.
4064 // This must be done before g_thread_init() is called.
4065 g_slice_set_config(G_SLICE_CONFIG_ALWAYS_MALLOC, 1);
4066 #endif
4067 g_thread_init(nullptr);
4068 #endif
4070 // init
4071 bool exit = false;
4072 int result = XRE_mainInit(&exit);
4073 if (result != 0 || exit)
4074 return result;
4076 // startup
4077 result = XRE_mainStartup(&exit);
4078 if (result != 0 || exit)
4079 return result;
4081 bool appInitiatedRestart = false;
4083 // Start the real application
4084 mScopedXPCom = new ScopedXPCOMStartup();
4085 if (!mScopedXPCom)
4086 return 1;
4088 rv = mScopedXPCom->Initialize();
4089 NS_ENSURE_SUCCESS(rv, 1);
4091 // run!
4092 rv = XRE_mainRun();
4094 #ifdef MOZ_INSTRUMENT_EVENT_LOOP
4095 mozilla::ShutdownEventTracing();
4096 #endif
4098 // Check for an application initiated restart. This is one that
4099 // corresponds to nsIAppStartup.quit(eRestart)
4100 if (rv == NS_SUCCESS_RESTART_APP || rv == NS_SUCCESS_RESTART_METRO_APP) {
4101 appInitiatedRestart = true;
4103 // We have an application restart don't do any shutdown checks here
4104 // In particular we don't want to poison IO for checking late-writes.
4105 gShutdownChecks = SCM_NOTHING;
4106 }
4108 if (!mShuttingDown) {
4109 #ifdef MOZ_ENABLE_XREMOTE
4110 // shut down the x remote proxy window
4111 if (mRemoteService) {
4112 mRemoteService->Shutdown();
4113 }
4114 #endif /* MOZ_ENABLE_XREMOTE */
4115 }
4117 delete mScopedXPCom;
4118 mScopedXPCom = nullptr;
4120 // unlock the profile after ScopedXPCOMStartup object (xpcom)
4121 // has gone out of scope. see bug #386739 for more details
4122 mProfileLock->Unlock();
4123 gProfileLock = nullptr;
4125 #if defined(MOZ_WIDGET_QT)
4126 nsQAppInstance::Release();
4127 #endif
4129 // Restart the app after XPCOM has been shut down cleanly.
4130 if (appInitiatedRestart) {
4131 RestoreStateForAppInitiatedRestart();
4133 // Ensure that these environment variables are set:
4134 SaveFileToEnvIfUnset("XRE_PROFILE_PATH", mProfD);
4135 SaveFileToEnvIfUnset("XRE_PROFILE_LOCAL_PATH", mProfLD);
4136 SaveWordToEnvIfUnset("XRE_PROFILE_NAME", mProfileName);
4138 #ifdef MOZ_WIDGET_GTK
4139 MOZ_gdk_display_close(mGdkDisplay);
4140 #endif
4142 #if defined(MOZ_METRO) && defined(XP_WIN)
4143 if (rv == NS_SUCCESS_RESTART_METRO_APP) {
4144 LaunchDefaultMetroBrowser();
4145 rv = NS_OK;
4146 } else
4147 #endif
4148 {
4149 rv = LaunchChild(mNativeApp, true);
4150 }
4152 #ifdef MOZ_CRASHREPORTER
4153 if (mAppData->flags & NS_XRE_ENABLE_CRASH_REPORTER)
4154 CrashReporter::UnsetExceptionHandler();
4155 #endif
4156 return rv == NS_ERROR_LAUNCHED_CHILD_PROCESS ? 0 : 1;
4157 }
4159 #ifdef MOZ_WIDGET_GTK
4160 // gdk_display_close also calls gdk_display_manager_set_default_display
4161 // appropriately when necessary.
4162 MOZ_gdk_display_close(mGdkDisplay);
4163 #endif
4165 #ifdef MOZ_CRASHREPORTER
4166 if (mAppData->flags & NS_XRE_ENABLE_CRASH_REPORTER)
4167 CrashReporter::UnsetExceptionHandler();
4168 #endif
4170 XRE_DeinitCommandLine();
4172 return NS_FAILED(rv) ? 1 : 0;
4173 }
4175 #if defined(MOZ_METRO) && defined(XP_WIN)
4176 extern bool XRE_MetroCoreApplicationRun();
4177 static XREMain* xreMainPtr;
4179 // must be called by the thread we want as the main thread
4180 nsresult
4181 XRE_metroStartup(bool runXREMain)
4182 {
4183 nsresult rv;
4185 bool exit = false;
4186 if (xreMainPtr->XRE_mainStartup(&exit) != 0 || exit)
4187 return NS_ERROR_FAILURE;
4189 // Start the real application
4190 xreMainPtr->mScopedXPCom = new ScopedXPCOMStartup();
4191 if (!xreMainPtr->mScopedXPCom)
4192 return NS_ERROR_FAILURE;
4194 rv = xreMainPtr->mScopedXPCom->Initialize();
4195 NS_ENSURE_SUCCESS(rv, rv);
4197 if (runXREMain) {
4198 rv = xreMainPtr->XRE_mainRun();
4199 NS_ENSURE_SUCCESS(rv, rv);
4200 }
4201 return NS_OK;
4202 }
4204 void
4205 XRE_metroShutdown()
4206 {
4207 delete xreMainPtr->mScopedXPCom;
4208 xreMainPtr->mScopedXPCom = nullptr;
4210 #ifdef MOZ_INSTRUMENT_EVENT_LOOP
4211 mozilla::ShutdownEventTracing();
4212 #endif
4214 // unlock the profile after ScopedXPCOMStartup object (xpcom)
4215 // has gone out of scope. see bug #386739 for more details
4216 xreMainPtr->mProfileLock->Unlock();
4217 gProfileLock = nullptr;
4219 #ifdef MOZ_CRASHREPORTER
4220 if (xreMainPtr->mAppData->flags & NS_XRE_ENABLE_CRASH_REPORTER)
4221 CrashReporter::UnsetExceptionHandler();
4222 #endif
4224 XRE_DeinitCommandLine();
4225 }
4227 class WinRTInitWrapper
4228 {
4229 public:
4230 WinRTInitWrapper() {
4231 mResult = ::RoInitialize(RO_INIT_MULTITHREADED);
4232 }
4233 ~WinRTInitWrapper() {
4234 if (SUCCEEDED(mResult)) {
4235 ::RoUninitialize();
4236 }
4237 }
4238 HRESULT mResult;
4239 };
4241 int
4242 XRE_mainMetro(int argc, char* argv[], const nsXREAppData* aAppData)
4243 {
4244 char aLocal;
4245 GeckoProfilerInitRAII profilerGuard(&aLocal);
4246 PROFILER_LABEL("Startup", "XRE_Main");
4248 mozilla::IOInterposerInit ioInterposerGuard;
4250 nsresult rv = NS_OK;
4252 xreMainPtr = new XREMain();
4253 if (!xreMainPtr) {
4254 return 1;
4255 }
4257 // Inits Winrt and COM underneath it.
4258 WinRTInitWrapper wrap;
4260 gArgc = argc;
4261 gArgv = argv;
4263 NS_ENSURE_TRUE(aAppData, 2);
4265 xreMainPtr->mAppData = new ScopedAppData(aAppData);
4266 if (!xreMainPtr->mAppData)
4267 return 1;
4268 // used throughout this file
4269 gAppData = xreMainPtr->mAppData;
4271 ScopedLogging log;
4273 // init
4274 bool exit = false;
4275 if (xreMainPtr->XRE_mainInit(&exit) != 0 || exit)
4276 return 1;
4278 // Located in widget, will call back into XRE_metroStartup and
4279 // XRE_metroShutdown above.
4280 if (!XRE_MetroCoreApplicationRun()) {
4281 return 1;
4282 }
4284 // XRE_metroShutdown should have already been called on the worker
4285 // thread that called XRE_metroStartup.
4286 NS_ASSERTION(!xreMainPtr->mScopedXPCom,
4287 "XPCOM Shutdown hasn't occured, and we are exiting.");
4288 return 0;
4289 }
4291 void SetWindowsEnvironment(WindowsEnvironmentType aEnvID);
4292 #endif // MOZ_METRO || !defined(XP_WIN)
4294 void
4295 XRE_StopLateWriteChecks(void) {
4296 mozilla::StopLateWriteChecks();
4297 }
4299 int
4300 XRE_main(int argc, char* argv[], const nsXREAppData* aAppData, uint32_t aFlags)
4301 {
4302 #if !defined(MOZ_METRO) || !defined(XP_WIN)
4303 XREMain main;
4304 int result = main.XRE_main(argc, argv, aAppData);
4305 mozilla::RecordShutdownEndTimeStamp();
4306 return result;
4307 #else
4308 if (aFlags == XRE_MAIN_FLAG_USE_METRO) {
4309 SetWindowsEnvironment(WindowsEnvironmentType_Metro);
4310 }
4312 // Desktop
4313 if (XRE_GetWindowsEnvironment() == WindowsEnvironmentType_Desktop) {
4314 XREMain main;
4315 int result = main.XRE_main(argc, argv, aAppData);
4316 mozilla::RecordShutdownEndTimeStamp();
4317 return result;
4318 }
4320 // Metro
4321 NS_ASSERTION(XRE_GetWindowsEnvironment() == WindowsEnvironmentType_Metro,
4322 "Unknown Windows environment");
4324 SetLastWinRunType(AHE_IMMERSIVE);
4326 int result = XRE_mainMetro(argc, argv, aAppData);
4327 mozilla::RecordShutdownEndTimeStamp();
4328 return result;
4329 #endif // MOZ_METRO || !defined(XP_WIN)
4330 }
4332 nsresult
4333 XRE_InitCommandLine(int aArgc, char* aArgv[])
4334 {
4335 nsresult rv = NS_OK;
4337 #if defined(OS_WIN)
4338 CommandLine::Init(aArgc, aArgv);
4339 #else
4341 // these leak on error, but that's OK: we'll just exit()
4342 char** canonArgs = new char*[aArgc];
4344 // get the canonical version of the binary's path
4345 nsCOMPtr<nsIFile> binFile;
4346 rv = XRE_GetBinaryPath(aArgv[0], getter_AddRefs(binFile));
4347 if (NS_FAILED(rv))
4348 return NS_ERROR_FAILURE;
4350 nsAutoCString canonBinPath;
4351 rv = binFile->GetNativePath(canonBinPath);
4352 if (NS_FAILED(rv))
4353 return NS_ERROR_FAILURE;
4355 canonArgs[0] = strdup(canonBinPath.get());
4357 for (int i = 1; i < aArgc; ++i) {
4358 if (aArgv[i]) {
4359 canonArgs[i] = strdup(aArgv[i]);
4360 }
4361 }
4363 NS_ASSERTION(!CommandLine::IsInitialized(), "Bad news!");
4364 CommandLine::Init(aArgc, canonArgs);
4366 for (int i = 0; i < aArgc; ++i)
4367 free(canonArgs[i]);
4368 delete[] canonArgs;
4369 #endif
4371 const char *path = nullptr;
4372 ArgResult ar = CheckArg("greomni", false, &path);
4373 if (ar == ARG_BAD) {
4374 PR_fprintf(PR_STDERR, "Error: argument -greomni requires a path argument\n");
4375 return NS_ERROR_FAILURE;
4376 }
4378 if (!path)
4379 return rv;
4381 nsCOMPtr<nsIFile> greOmni;
4382 rv = XRE_GetFileFromPath(path, getter_AddRefs(greOmni));
4383 if (NS_FAILED(rv)) {
4384 PR_fprintf(PR_STDERR, "Error: argument -greomni requires a valid path\n");
4385 return rv;
4386 }
4388 ar = CheckArg("appomni", false, &path);
4389 if (ar == ARG_BAD) {
4390 PR_fprintf(PR_STDERR, "Error: argument -appomni requires a path argument\n");
4391 return NS_ERROR_FAILURE;
4392 }
4394 nsCOMPtr<nsIFile> appOmni;
4395 if (path) {
4396 rv = XRE_GetFileFromPath(path, getter_AddRefs(appOmni));
4397 if (NS_FAILED(rv)) {
4398 PR_fprintf(PR_STDERR, "Error: argument -appomni requires a valid path\n");
4399 return rv;
4400 }
4401 }
4403 mozilla::Omnijar::Init(greOmni, appOmni);
4404 return rv;
4405 }
4407 nsresult
4408 XRE_DeinitCommandLine()
4409 {
4410 nsresult rv = NS_OK;
4412 CommandLine::Terminate();
4414 return rv;
4415 }
4417 GeckoProcessType
4418 XRE_GetProcessType()
4419 {
4420 return mozilla::startup::sChildProcessType;
4421 }
4423 bool
4424 mozilla::BrowserTabsRemote()
4425 {
4426 if (!gBrowserTabsRemoteInitialized) {
4427 gBrowserTabsRemote = Preferences::GetBool("browser.tabs.remote", false);
4428 gBrowserTabsRemoteInitialized = true;
4429 }
4431 return gBrowserTabsRemote;
4432 }
4434 void
4435 SetupErrorHandling(const char* progname)
4436 {
4437 #ifdef XP_WIN
4438 /* On Windows XPSP3 and Windows Vista if DEP is configured off-by-default
4439 we still want DEP protection: enable it explicitly and programmatically.
4441 This function is not available on WinXPSP2 so we dynamically load it.
4442 */
4444 HMODULE kernel32 = GetModuleHandleW(L"kernel32.dll");
4445 SetProcessDEPPolicyFunc _SetProcessDEPPolicy =
4446 (SetProcessDEPPolicyFunc) GetProcAddress(kernel32, "SetProcessDEPPolicy");
4447 if (_SetProcessDEPPolicy)
4448 _SetProcessDEPPolicy(PROCESS_DEP_ENABLE);
4449 #endif
4451 #ifdef XP_WIN32
4452 // Suppress the "DLL Foo could not be found" dialog, such that if dependent
4453 // libraries (such as GDI+) are not preset, we gracefully fail to load those
4454 // XPCOM components, instead of being ungraceful.
4455 UINT realMode = SetErrorMode(0);
4456 realMode |= SEM_FAILCRITICALERRORS;
4457 // If XRE_NO_WINDOWS_CRASH_DIALOG is set, suppress displaying the "This
4458 // application has crashed" dialog box. This is mainly useful for
4459 // automated testing environments, e.g. tinderbox, where there's no need
4460 // for a dozen of the dialog boxes to litter the console
4461 if (getenv("XRE_NO_WINDOWS_CRASH_DIALOG"))
4462 realMode |= SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX;
4464 SetErrorMode(realMode);
4466 #endif
4468 #if defined (DEBUG) && defined(XP_WIN)
4469 // Send MSCRT Warnings, Errors and Assertions to stderr.
4470 // See http://msdn.microsoft.com/en-us/library/1y71x448(v=VS.80).aspx
4471 // and http://msdn.microsoft.com/en-us/library/a68f826y(v=VS.80).aspx.
4473 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
4474 _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
4475 _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
4476 _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
4477 _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
4478 _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
4480 _CrtSetReportHook(MSCRTReportHook);
4481 #endif
4483 InstallSignalHandlers(progname);
4485 // Unbuffer stdout, needed for tinderbox tests.
4486 setbuf(stdout, 0);
4487 }