Merge fx-team to m-c.
[gecko.git] / toolkit / xre / nsAppRunner.cpp
blob57f1cc45156b498209db7abe5fa0a31df95716ed
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(XP_OS2) && defined(MOZ_OS2_HIGH_MEMORY)
7 // os2safe.h has to be included before os2.h, needed for high mem
8 #include <os2safe.h>
9 #endif
11 #if defined(MOZ_WIDGET_QT)
12 #include <QApplication>
13 #include <QStringList>
14 #include "nsQAppInstance.h"
15 #if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0))
16 #include <QInputContextFactory>
17 #include <QInputContext>
18 #endif
19 #endif // MOZ_WIDGET_QT
21 #include "mozilla/dom/ContentParent.h"
22 #include "mozilla/dom/ContentChild.h"
24 #include "mozilla/Attributes.h"
25 #include "mozilla/Likely.h"
26 #include "mozilla/Poison.h"
27 #include "mozilla/Telemetry.h"
28 #include "mozilla/Util.h"
30 #include "nsAppRunner.h"
31 #include "mozilla/AppData.h"
32 #include "nsUpdateDriver.h"
33 #include "ProfileReset.h"
35 #ifdef MOZ_INSTRUMENT_EVENT_LOOP
36 #include "EventTracer.h"
37 #endif
39 #ifdef XP_MACOSX
40 #include "nsVersionComparator.h"
41 #include "MacLaunchHelper.h"
42 #include "MacApplicationDelegate.h"
43 #include "MacAutoreleasePool.h"
44 // these are needed for sysctl
45 #include <sys/types.h>
46 #include <sys/sysctl.h>
47 #endif
49 #ifdef XP_OS2
50 #include "private/pprthred.h"
51 #endif
52 #include "prmem.h"
53 #include "prnetdb.h"
54 #include "prprf.h"
55 #include "prproces.h"
56 #include "prenv.h"
58 #include "nsIAppShellService.h"
59 #include "nsIAppStartup.h"
60 #include "nsIAppStartupNotifier.h"
61 #include "nsIMutableArray.h"
62 #include "nsICategoryManager.h"
63 #include "nsIChromeRegistry.h"
64 #include "nsICommandLineRunner.h"
65 #include "nsIComponentManager.h"
66 #include "nsIComponentRegistrar.h"
67 #include "nsIContentHandler.h"
68 #include "nsIDialogParamBlock.h"
69 #include "nsIDOMWindow.h"
70 #include "mozilla/ModuleUtils.h"
71 #include "nsIIOService2.h"
72 #include "nsIObserverService.h"
73 #include "nsINativeAppSupport.h"
74 #include "nsIProcess.h"
75 #include "nsIProfileUnlocker.h"
76 #include "nsIPromptService.h"
77 #include "nsIServiceManager.h"
78 #include "nsIStringBundle.h"
79 #include "nsISupportsPrimitives.h"
80 #include "nsIToolkitChromeRegistry.h"
81 #include "nsIToolkitProfile.h"
82 #include "nsIToolkitProfileService.h"
83 #include "nsIURI.h"
84 #include "nsIWindowCreator.h"
85 #include "nsIWindowMediator.h"
86 #include "nsIWindowWatcher.h"
87 #include "nsIXULAppInfo.h"
88 #include "nsIXULRuntime.h"
89 #include "nsPIDOMWindow.h"
90 #include "nsIBaseWindow.h"
91 #include "nsIWidget.h"
92 #include "nsIDocShell.h"
93 #include "nsAppShellCID.h"
94 #include "mozilla/scache/StartupCache.h"
96 #include "mozilla/unused.h"
98 #ifdef XP_WIN
99 #include "nsIWinAppHelper.h"
100 #include <windows.h>
101 #include "cairo/cairo-features.h"
102 #include "mozilla/WindowsVersion.h"
103 #ifdef MOZ_METRO
104 #include <roapi.h>
105 #endif
107 #ifndef PROCESS_DEP_ENABLE
108 #define PROCESS_DEP_ENABLE 0x1
109 #endif
110 #endif
112 #include "nsCRT.h"
113 #include "nsCOMPtr.h"
114 #include "nsDirectoryServiceDefs.h"
115 #include "nsDirectoryServiceUtils.h"
116 #include "nsEmbedCID.h"
117 #include "nsNetUtil.h"
118 #include "nsReadableUtils.h"
119 #include "nsXPCOM.h"
120 #include "nsXPCOMCIDInternal.h"
121 #include "nsXPIDLString.h"
122 #include "nsPrintfCString.h"
123 #include "nsVersionComparator.h"
125 #include "nsAppDirectoryServiceDefs.h"
126 #include "nsXULAppAPI.h"
127 #include "nsXREDirProvider.h"
128 #include "nsToolkitCompsCID.h"
130 #include "nsINIParser.h"
131 #include "mozilla/Omnijar.h"
132 #include "mozilla/StartupTimeline.h"
133 #include "mozilla/LateWriteChecks.h"
135 #include <stdlib.h>
137 // for old system jemalloc version check
138 #if !defined(MOZ_MEMORY) && defined(__NetBSD__)
139 #include <sys/param.h>
140 #endif
142 #ifdef XP_UNIX
143 #include <sys/stat.h>
144 #include <unistd.h>
145 #include <pwd.h>
146 #endif
148 #ifdef XP_WIN
149 #include <process.h>
150 #include <shlobj.h>
151 #include "nsThreadUtils.h"
152 #include <comutil.h>
153 #include <Wbemidl.h>
154 #endif
156 #ifdef XP_MACOSX
157 #include "nsILocalFileMac.h"
158 #include "nsCommandLineServiceMac.h"
159 #endif
161 // for X remote support
162 #ifdef MOZ_ENABLE_XREMOTE
163 #include "XRemoteClient.h"
164 #include "nsIRemoteService.h"
165 #endif
167 #ifdef NS_TRACE_MALLOC
168 #include "nsTraceMalloc.h"
169 #endif
171 #if defined(DEBUG) && defined(XP_WIN32)
172 #include <malloc.h>
173 #endif
175 #if defined (XP_MACOSX)
176 #include <Carbon/Carbon.h>
177 #endif
179 #ifdef DEBUG
180 #include "prlog.h"
181 #endif
183 #ifdef MOZ_JPROF
184 #include "jprof.h"
185 #endif
187 #ifdef MOZ_CRASHREPORTER
188 #include "nsExceptionHandler.h"
189 #include "nsICrashReporter.h"
190 #define NS_CRASHREPORTER_CONTRACTID "@mozilla.org/toolkit/crash-reporter;1"
191 #include "nsIPrefService.h"
192 #include "mozilla/Preferences.h"
193 #endif
195 #include "base/command_line.h"
196 #ifdef MOZ_ENABLE_TESTS
197 #include "GTestRunner.h"
198 #endif
200 #ifdef MOZ_WIDGET_ANDROID
201 #include "AndroidBridge.h"
202 #endif
204 extern uint32_t gRestartMode;
205 extern void InstallSignalHandlers(const char *ProgramName);
206 #include "nsX11ErrorHandler.h"
208 #define FILE_COMPATIBILITY_INFO NS_LITERAL_CSTRING("compatibility.ini")
209 #define FILE_INVALIDATE_CACHES NS_LITERAL_CSTRING(".purgecaches")
211 int gArgc;
212 char **gArgv;
214 static const char gToolkitVersion[] = NS_STRINGIFY(GRE_MILESTONE);
215 static const char gToolkitBuildID[] = NS_STRINGIFY(GRE_BUILDID);
217 static nsIProfileLock* gProfileLock;
219 int gRestartArgc;
220 char **gRestartArgv;
222 #ifdef MOZ_WIDGET_QT
223 static int gQtOnlyArgc;
224 static char **gQtOnlyArgv;
225 #endif
227 #if defined(MOZ_WIDGET_GTK)
228 #if defined(DEBUG) || defined(NS_BUILD_REFCNT_LOGGING) \
229 || defined(NS_TRACE_MALLOC)
230 #define CLEANUP_MEMORY 1
231 #define PANGO_ENABLE_BACKEND
232 #include <pango/pangofc-fontmap.h>
233 #endif
234 #include <gtk/gtk.h>
235 #ifdef MOZ_X11
236 #include <gdk/gdkx.h>
237 #endif /* MOZ_X11 */
238 #include "nsGTKToolkit.h"
239 #endif
240 #include "BinaryPath.h"
242 #ifdef MOZ_LINKER
243 extern "C" MFBT_API bool IsSignalHandlingBroken();
244 #endif
246 namespace mozilla {
247 int (*RunGTest)() = 0;
250 using namespace mozilla;
251 using mozilla::unused;
252 using mozilla::scache::StartupCache;
253 using mozilla::dom::ContentParent;
254 using mozilla::dom::ContentChild;
256 // Save literal putenv string to environment variable.
257 static void
258 SaveToEnv(const char *putenv)
260 char *expr = strdup(putenv);
261 if (expr)
262 PR_SetEnv(expr);
263 // We intentionally leak |expr| here since it is required by PR_SetEnv.
266 // Tests that an environment variable exists and has a value
267 static bool
268 EnvHasValue(const char *name)
270 const char *val = PR_GetEnv(name);
271 return (val && *val);
274 // Save the given word to the specified environment variable.
275 static void
276 SaveWordToEnv(const char *name, const nsACString & word)
278 char *expr = PR_smprintf("%s=%s", name, PromiseFlatCString(word).get());
279 if (expr)
280 PR_SetEnv(expr);
281 // We intentionally leak |expr| here since it is required by PR_SetEnv.
284 // Save the path of the given file to the specified environment variable.
285 static void
286 SaveFileToEnv(const char *name, nsIFile *file)
288 #ifdef XP_WIN
289 nsAutoString path;
290 file->GetPath(path);
291 SetEnvironmentVariableW(NS_ConvertASCIItoUTF16(name).get(), path.get());
292 #else
293 nsAutoCString path;
294 file->GetNativePath(path);
295 SaveWordToEnv(name, path);
296 #endif
299 // Load the path of a file saved with SaveFileToEnv
300 static already_AddRefed<nsIFile>
301 GetFileFromEnv(const char *name)
303 nsresult rv;
304 nsCOMPtr<nsIFile> file;
306 #ifdef XP_WIN
307 WCHAR path[_MAX_PATH];
308 if (!GetEnvironmentVariableW(NS_ConvertASCIItoUTF16(name).get(),
309 path, _MAX_PATH))
310 return nullptr;
312 rv = NS_NewLocalFile(nsDependentString(path), true, getter_AddRefs(file));
313 if (NS_FAILED(rv))
314 return nullptr;
316 return file.forget();
317 #else
318 const char *arg = PR_GetEnv(name);
319 if (!arg || !*arg)
320 return nullptr;
322 rv = NS_NewNativeLocalFile(nsDependentCString(arg), true,
323 getter_AddRefs(file));
324 if (NS_FAILED(rv))
325 return nullptr;
327 return file.forget();
328 #endif
331 // Save the path of the given word to the specified environment variable
332 // provided the environment variable does not have a value.
333 static void
334 SaveWordToEnvIfUnset(const char *name, const nsACString & word)
336 if (!EnvHasValue(name))
337 SaveWordToEnv(name, word);
340 // Save the path of the given file to the specified environment variable
341 // provided the environment variable does not have a value.
342 static void
343 SaveFileToEnvIfUnset(const char *name, nsIFile *file)
345 if (!EnvHasValue(name))
346 SaveFileToEnv(name, file);
349 static bool
350 strimatch(const char* lowerstr, const char* mixedstr)
352 while(*lowerstr) {
353 if (!*mixedstr) return false; // mixedstr is shorter
354 if (tolower(*mixedstr) != *lowerstr) return false; // no match
356 ++lowerstr;
357 ++mixedstr;
360 if (*mixedstr) return false; // lowerstr is shorter
362 return true;
366 * Output a string to the user. This method is really only meant to be used to
367 * output last-ditch error messages designed for developers NOT END USERS.
369 * @param isError
370 * Pass true to indicate severe errors.
371 * @param fmt
372 * printf-style format string followed by arguments.
374 static void Output(bool isError, const char *fmt, ... )
376 va_list ap;
377 va_start(ap, fmt);
379 #if defined(XP_WIN) && !MOZ_WINCONSOLE
380 char *msg = PR_vsmprintf(fmt, ap);
381 if (msg)
383 UINT flags = MB_OK;
384 if (isError)
385 flags |= MB_ICONERROR;
386 else
387 flags |= MB_ICONINFORMATION;
389 wchar_t wide_msg[1024];
390 MultiByteToWideChar(CP_ACP,
392 msg,
394 wide_msg,
395 sizeof(wide_msg) / sizeof(wchar_t));
397 MessageBoxW(nullptr, wide_msg, L"XULRunner", flags);
398 PR_smprintf_free(msg);
400 #else
401 vfprintf(stderr, fmt, ap);
402 #endif
404 va_end(ap);
407 enum RemoteResult {
408 REMOTE_NOT_FOUND = 0,
409 REMOTE_FOUND = 1,
410 REMOTE_ARG_BAD = 2
413 enum ArgResult {
414 ARG_NONE = 0,
415 ARG_FOUND = 1,
416 ARG_BAD = 2 // you wanted a param, but there isn't one
419 static void RemoveArg(char **argv)
421 do {
422 *argv = *(argv + 1);
423 ++argv;
424 } while (*argv);
426 --gArgc;
430 * Check for a commandline flag. If the flag takes a parameter, the
431 * parameter is returned in aParam. Flags may be in the form -arg or
432 * --arg (or /arg on win32/OS2).
434 * @param aArg the parameter to check. Must be lowercase.
435 * @param aCheckOSInt if true returns ARG_BAD if the osint argument is present
436 * when aArg is also present.
437 * @param aParam if non-null, the -arg <data> will be stored in this pointer.
438 * This is *not* allocated, but rather a pointer to the argv data.
439 * @param aRemArg if true, the argument is removed from the gArgv array.
441 static ArgResult
442 CheckArg(const char* aArg, bool aCheckOSInt = false, const char **aParam = nullptr, bool aRemArg = true)
444 NS_ABORT_IF_FALSE(gArgv, "gArgv must be initialized before CheckArg()");
446 char **curarg = gArgv + 1; // skip argv[0]
447 ArgResult ar = ARG_NONE;
449 while (*curarg) {
450 char *arg = curarg[0];
452 if (arg[0] == '-'
453 #if defined(XP_WIN) || defined(XP_OS2)
454 || *arg == '/'
455 #endif
457 ++arg;
458 if (*arg == '-')
459 ++arg;
461 if (strimatch(aArg, arg)) {
462 if (aRemArg)
463 RemoveArg(curarg);
464 if (!aParam) {
465 ar = ARG_FOUND;
466 break;
469 if (*curarg) {
470 if (**curarg == '-'
471 #if defined(XP_WIN) || defined(XP_OS2)
472 || **curarg == '/'
473 #endif
475 return ARG_BAD;
477 *aParam = *curarg;
478 if (aRemArg)
479 RemoveArg(curarg);
480 ar = ARG_FOUND;
481 break;
483 return ARG_BAD;
487 ++curarg;
490 if (aCheckOSInt && ar == ARG_FOUND) {
491 ArgResult arOSInt = CheckArg("osint");
492 if (arOSInt == ARG_FOUND) {
493 ar = ARG_BAD;
494 PR_fprintf(PR_STDERR, "Error: argument -osint is invalid\n");
498 return ar;
501 #if defined(XP_WIN)
503 * Check for a commandline flag from the windows shell and remove it from the
504 * argv used when restarting. Flags MUST be in the form -arg.
506 * @param aArg the parameter to check. Must be lowercase.
508 static ArgResult
509 CheckArgShell(const char* aArg)
511 char **curarg = gRestartArgv + 1; // skip argv[0]
513 while (*curarg) {
514 char *arg = curarg[0];
516 if (arg[0] == '-') {
517 ++arg;
519 if (strimatch(aArg, arg)) {
520 do {
521 *curarg = *(curarg + 1);
522 ++curarg;
523 } while (*curarg);
525 --gRestartArgc;
527 return ARG_FOUND;
531 ++curarg;
534 return ARG_NONE;
538 * Enabled Native App Support to process DDE messages when the app needs to
539 * restart and the app has been launched by the Windows shell to open an url.
540 * When aWait is false this will process the DDE events manually. This prevents
541 * Windows from displaying an error message due to the DDE message not being
542 * acknowledged.
544 static void
545 ProcessDDE(nsINativeAppSupport* aNative, bool aWait)
547 // When the app is launched by the windows shell the windows shell
548 // expects the app to be available for DDE messages and if it isn't
549 // windows displays an error dialog. To prevent the error the DDE server
550 // is enabled and pending events are processed when the app needs to
551 // restart after it was launched by the shell with the requestpending
552 // argument. The requestpending pending argument is removed to
553 // differentiate it from being launched when an app restart is not
554 // required.
555 ArgResult ar;
556 ar = CheckArgShell("requestpending");
557 if (ar == ARG_FOUND) {
558 aNative->Enable(); // enable win32 DDE responses
559 if (aWait) {
560 nsIThread *thread = NS_GetCurrentThread();
561 // This is just a guesstimate based on testing different values.
562 // If count is 8 or less windows will display an error dialog.
563 int32_t count = 20;
564 while(--count >= 0) {
565 NS_ProcessNextEvent(thread);
566 PR_Sleep(PR_MillisecondsToInterval(1));
571 #endif
573 bool gSafeMode = false;
576 * The nsXULAppInfo object implements nsIFactory so that it can be its own
577 * singleton.
579 class nsXULAppInfo : public nsIXULAppInfo,
580 #ifdef XP_WIN
581 public nsIWinAppHelper,
582 #endif
583 #ifdef MOZ_CRASHREPORTER
584 public nsICrashReporter,
585 #endif
586 public nsIXULRuntime
589 public:
590 nsXULAppInfo() {}
591 NS_DECL_ISUPPORTS_INHERITED
592 NS_DECL_NSIXULAPPINFO
593 NS_DECL_NSIXULRUNTIME
594 #ifdef MOZ_CRASHREPORTER
595 NS_DECL_NSICRASHREPORTER
596 #endif
597 #ifdef XP_WIN
598 NS_DECL_NSIWINAPPHELPER
599 #endif
602 NS_INTERFACE_MAP_BEGIN(nsXULAppInfo)
603 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXULRuntime)
604 NS_INTERFACE_MAP_ENTRY(nsIXULRuntime)
605 #ifdef XP_WIN
606 NS_INTERFACE_MAP_ENTRY(nsIWinAppHelper)
607 #endif
608 #ifdef MOZ_CRASHREPORTER
609 NS_INTERFACE_MAP_ENTRY(nsICrashReporter)
610 #endif
611 NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIXULAppInfo, gAppData ||
612 XRE_GetProcessType() == GeckoProcessType_Content)
613 NS_INTERFACE_MAP_END
615 NS_IMETHODIMP_(nsrefcnt)
616 nsXULAppInfo::AddRef()
618 return 1;
621 NS_IMETHODIMP_(nsrefcnt)
622 nsXULAppInfo::Release()
624 return 1;
627 NS_IMETHODIMP
628 nsXULAppInfo::GetVendor(nsACString& aResult)
630 if (XRE_GetProcessType() == GeckoProcessType_Content) {
631 return NS_ERROR_NOT_AVAILABLE;
633 aResult.Assign(gAppData->vendor);
635 return NS_OK;
638 NS_IMETHODIMP
639 nsXULAppInfo::GetName(nsACString& aResult)
641 if (XRE_GetProcessType() == GeckoProcessType_Content) {
642 ContentChild* cc = ContentChild::GetSingleton();
643 aResult = cc->GetAppInfo().name;
644 return NS_OK;
646 aResult.Assign(gAppData->name);
648 return NS_OK;
651 NS_IMETHODIMP
652 nsXULAppInfo::GetID(nsACString& aResult)
654 if (XRE_GetProcessType() == GeckoProcessType_Content) {
655 return NS_ERROR_NOT_AVAILABLE;
657 aResult.Assign(gAppData->ID);
659 return NS_OK;
662 NS_IMETHODIMP
663 nsXULAppInfo::GetVersion(nsACString& aResult)
665 if (XRE_GetProcessType() == GeckoProcessType_Content) {
666 ContentChild* cc = ContentChild::GetSingleton();
667 aResult = cc->GetAppInfo().version;
668 return NS_OK;
670 aResult.Assign(gAppData->version);
672 return NS_OK;
675 NS_IMETHODIMP
676 nsXULAppInfo::GetPlatformVersion(nsACString& aResult)
678 aResult.Assign(gToolkitVersion);
680 return NS_OK;
683 NS_IMETHODIMP
684 nsXULAppInfo::GetAppBuildID(nsACString& aResult)
686 if (XRE_GetProcessType() == GeckoProcessType_Content) {
687 ContentChild* cc = ContentChild::GetSingleton();
688 aResult = cc->GetAppInfo().buildID;
689 return NS_OK;
691 aResult.Assign(gAppData->buildID);
693 return NS_OK;
696 NS_IMETHODIMP
697 nsXULAppInfo::GetPlatformBuildID(nsACString& aResult)
699 aResult.Assign(gToolkitBuildID);
701 return NS_OK;
704 NS_IMETHODIMP
705 nsXULAppInfo::GetUAName(nsACString& aResult)
707 if (XRE_GetProcessType() == GeckoProcessType_Content) {
708 ContentChild* cc = ContentChild::GetSingleton();
709 aResult = cc->GetAppInfo().UAName;
710 return NS_OK;
712 aResult.Assign(gAppData->UAName);
714 return NS_OK;
717 NS_IMETHODIMP
718 nsXULAppInfo::GetLogConsoleErrors(bool *aResult)
720 *aResult = gLogConsoleErrors;
721 return NS_OK;
724 NS_IMETHODIMP
725 nsXULAppInfo::SetLogConsoleErrors(bool aValue)
727 gLogConsoleErrors = aValue;
728 return NS_OK;
731 NS_IMETHODIMP
732 nsXULAppInfo::GetInSafeMode(bool *aResult)
734 *aResult = gSafeMode;
735 return NS_OK;
738 NS_IMETHODIMP
739 nsXULAppInfo::GetOS(nsACString& aResult)
741 aResult.AssignLiteral(OS_TARGET);
742 return NS_OK;
745 NS_IMETHODIMP
746 nsXULAppInfo::GetXPCOMABI(nsACString& aResult)
748 #ifdef TARGET_XPCOM_ABI
749 aResult.AssignLiteral(TARGET_XPCOM_ABI);
750 return NS_OK;
751 #else
752 return NS_ERROR_NOT_AVAILABLE;
753 #endif
756 NS_IMETHODIMP
757 nsXULAppInfo::GetWidgetToolkit(nsACString& aResult)
759 aResult.AssignLiteral(MOZ_WIDGET_TOOLKIT);
760 return NS_OK;
763 // Ensure that the GeckoProcessType enum, defined in xpcom/build/nsXULAppAPI.h,
764 // is synchronized with the const unsigned longs defined in
765 // xpcom/system/nsIXULRuntime.idl.
766 #define SYNC_ENUMS(a,b) \
767 static_assert(nsIXULRuntime::PROCESS_TYPE_ ## a == \
768 static_cast<int>(GeckoProcessType_ ## b), \
769 "GeckoProcessType in nsXULAppAPI.h not synchronized with nsIXULRuntime.idl");
771 SYNC_ENUMS(DEFAULT, Default)
772 SYNC_ENUMS(PLUGIN, Plugin)
773 SYNC_ENUMS(CONTENT, Content)
774 SYNC_ENUMS(IPDLUNITTEST, IPDLUnitTest)
776 // .. and ensure that that is all of them:
777 static_assert(GeckoProcessType_IPDLUnitTest + 1 == GeckoProcessType_End,
778 "Did not find the final GeckoProcessType");
780 NS_IMETHODIMP
781 nsXULAppInfo::GetProcessType(uint32_t* aResult)
783 NS_ENSURE_ARG_POINTER(aResult);
784 *aResult = XRE_GetProcessType();
785 return NS_OK;
788 NS_IMETHODIMP
789 nsXULAppInfo::EnsureContentProcess()
791 if (XRE_GetProcessType() != GeckoProcessType_Default)
792 return NS_ERROR_NOT_AVAILABLE;
794 nsRefPtr<ContentParent> unused = ContentParent::GetNewOrUsed();
795 return NS_OK;
798 NS_IMETHODIMP
799 nsXULAppInfo::InvalidateCachesOnRestart()
801 nsCOMPtr<nsIFile> file;
802 nsresult rv = NS_GetSpecialDirectory(NS_APP_PROFILE_DIR_STARTUP,
803 getter_AddRefs(file));
804 if (NS_FAILED(rv))
805 return rv;
806 if (!file)
807 return NS_ERROR_NOT_AVAILABLE;
809 file->AppendNative(FILE_COMPATIBILITY_INFO);
811 nsINIParser parser;
812 rv = parser.Init(file);
813 if (NS_FAILED(rv)) {
814 // This fails if compatibility.ini is not there, so we'll
815 // flush the caches on the next restart anyways.
816 return NS_OK;
819 nsAutoCString buf;
820 rv = parser.GetString("Compatibility", "InvalidateCaches", buf);
822 if (NS_FAILED(rv)) {
823 PRFileDesc *fd = nullptr;
824 file->OpenNSPRFileDesc(PR_RDWR | PR_APPEND, 0600, &fd);
825 if (!fd) {
826 NS_ERROR("could not create output stream");
827 return NS_ERROR_NOT_AVAILABLE;
829 static const char kInvalidationHeader[] = NS_LINEBREAK "InvalidateCaches=1" NS_LINEBREAK;
830 PR_Write(fd, kInvalidationHeader, sizeof(kInvalidationHeader) - 1);
831 PR_Close(fd);
833 return NS_OK;
836 NS_IMETHODIMP
837 nsXULAppInfo::GetReplacedLockTime(PRTime *aReplacedLockTime)
839 if (!gProfileLock)
840 return NS_ERROR_NOT_AVAILABLE;
841 gProfileLock->GetReplacedLockTime(aReplacedLockTime);
842 return NS_OK;
845 NS_IMETHODIMP
846 nsXULAppInfo::GetLastRunCrashID(nsAString &aLastRunCrashID)
848 #ifdef MOZ_CRASHREPORTER
849 CrashReporter::GetLastRunCrashID(aLastRunCrashID);
850 return NS_OK;
851 #else
852 return NS_ERROR_NOT_IMPLEMENTED;
853 #endif
856 #ifdef XP_WIN
857 // Matches the enum in WinNT.h for the Vista SDK but renamed so that we can
858 // safely build with the Vista SDK and without it.
859 typedef enum
861 VistaTokenElevationTypeDefault = 1,
862 VistaTokenElevationTypeFull,
863 VistaTokenElevationTypeLimited
864 } VISTA_TOKEN_ELEVATION_TYPE;
866 // avoid collision with TokeElevationType enum in WinNT.h
867 // of the Vista SDK
868 #define VistaTokenElevationType static_cast< TOKEN_INFORMATION_CLASS >( 18 )
870 NS_IMETHODIMP
871 nsXULAppInfo::GetUserCanElevate(bool *aUserCanElevate)
873 HANDLE hToken;
875 VISTA_TOKEN_ELEVATION_TYPE elevationType;
876 DWORD dwSize;
878 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken) ||
879 !GetTokenInformation(hToken, VistaTokenElevationType, &elevationType,
880 sizeof(elevationType), &dwSize)) {
881 *aUserCanElevate = false;
883 else {
884 // The possible values returned for elevationType and their meanings are:
885 // TokenElevationTypeDefault: The token does not have a linked token
886 // (e.g. UAC disabled or a standard user, so they can't be elevated)
887 // TokenElevationTypeFull: The token is linked to an elevated token
888 // (e.g. UAC is enabled and the user is already elevated so they can't
889 // be elevated again)
890 // TokenElevationTypeLimited: The token is linked to a limited token
891 // (e.g. UAC is enabled and the user is not elevated, so they can be
892 // elevated)
893 *aUserCanElevate = (elevationType == VistaTokenElevationTypeLimited);
896 if (hToken)
897 CloseHandle(hToken);
899 return NS_OK;
901 #endif
903 #ifdef MOZ_CRASHREPORTER
904 NS_IMETHODIMP
905 nsXULAppInfo::GetEnabled(bool *aEnabled)
907 *aEnabled = CrashReporter::GetEnabled();
908 return NS_OK;
911 NS_IMETHODIMP
912 nsXULAppInfo::SetEnabled(bool aEnabled)
914 if (aEnabled) {
915 if (CrashReporter::GetEnabled())
916 // no point in erroring for double-enabling
917 return NS_OK;
919 nsCOMPtr<nsIFile> xreDirectory;
920 if (gAppData) {
921 xreDirectory = gAppData->xreDirectory;
923 else {
924 // We didn't get started through XRE_Main, probably
925 nsCOMPtr<nsIFile> greDir;
926 NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(greDir));
927 if (!greDir)
928 return NS_ERROR_FAILURE;
930 xreDirectory = do_QueryInterface(greDir);
931 if (!xreDirectory)
932 return NS_ERROR_FAILURE;
934 return CrashReporter::SetExceptionHandler(xreDirectory, true);
936 else {
937 if (!CrashReporter::GetEnabled())
938 // no point in erroring for double-disabling
939 return NS_OK;
941 return CrashReporter::UnsetExceptionHandler();
945 NS_IMETHODIMP
946 nsXULAppInfo::GetServerURL(nsIURL** aServerURL)
948 if (!CrashReporter::GetEnabled())
949 return NS_ERROR_NOT_INITIALIZED;
951 nsAutoCString data;
952 if (!CrashReporter::GetServerURL(data)) {
953 return NS_ERROR_FAILURE;
955 nsCOMPtr<nsIURI> uri;
956 NS_NewURI(getter_AddRefs(uri), data);
957 if (!uri)
958 return NS_ERROR_FAILURE;
960 nsCOMPtr<nsIURL> url;
961 url = do_QueryInterface(uri);
962 NS_ADDREF(*aServerURL = url);
964 return NS_OK;
967 NS_IMETHODIMP
968 nsXULAppInfo::SetServerURL(nsIURL* aServerURL)
970 bool schemeOk;
971 // only allow https or http URLs
972 nsresult rv = aServerURL->SchemeIs("https", &schemeOk);
973 NS_ENSURE_SUCCESS(rv, rv);
974 if (!schemeOk) {
975 rv = aServerURL->SchemeIs("http", &schemeOk);
976 NS_ENSURE_SUCCESS(rv, rv);
978 if (!schemeOk)
979 return NS_ERROR_INVALID_ARG;
981 nsAutoCString spec;
982 rv = aServerURL->GetSpec(spec);
983 NS_ENSURE_SUCCESS(rv, rv);
985 return CrashReporter::SetServerURL(spec);
988 NS_IMETHODIMP
989 nsXULAppInfo::GetMinidumpPath(nsIFile** aMinidumpPath)
991 if (!CrashReporter::GetEnabled())
992 return NS_ERROR_NOT_INITIALIZED;
994 nsAutoString path;
995 if (!CrashReporter::GetMinidumpPath(path))
996 return NS_ERROR_FAILURE;
998 nsresult rv = NS_NewLocalFile(path, false, aMinidumpPath);
999 NS_ENSURE_SUCCESS(rv, rv);
1000 return NS_OK;
1003 NS_IMETHODIMP
1004 nsXULAppInfo::SetMinidumpPath(nsIFile* aMinidumpPath)
1006 nsAutoString path;
1007 nsresult rv = aMinidumpPath->GetPath(path);
1008 NS_ENSURE_SUCCESS(rv, rv);
1009 return CrashReporter::SetMinidumpPath(path);
1012 NS_IMETHODIMP
1013 nsXULAppInfo::AnnotateCrashReport(const nsACString& key,
1014 const nsACString& data)
1016 return CrashReporter::AnnotateCrashReport(key, data);
1019 NS_IMETHODIMP
1020 nsXULAppInfo::AppendAppNotesToCrashReport(const nsACString& data)
1022 return CrashReporter::AppendAppNotesToCrashReport(data);
1025 NS_IMETHODIMP
1026 nsXULAppInfo::RegisterAppMemory(uint64_t pointer,
1027 uint64_t len)
1029 return CrashReporter::RegisterAppMemory((void *)pointer, len);
1032 NS_IMETHODIMP
1033 nsXULAppInfo::WriteMinidumpForException(void* aExceptionInfo)
1035 #ifdef XP_WIN32
1036 return CrashReporter::WriteMinidumpForException(static_cast<EXCEPTION_POINTERS*>(aExceptionInfo));
1037 #else
1038 return NS_ERROR_NOT_IMPLEMENTED;
1039 #endif
1042 NS_IMETHODIMP
1043 nsXULAppInfo::AppendObjCExceptionInfoToAppNotes(void* aException)
1045 #ifdef XP_MACOSX
1046 return CrashReporter::AppendObjCExceptionInfoToAppNotes(aException);
1047 #else
1048 return NS_ERROR_NOT_IMPLEMENTED;
1049 #endif
1052 NS_IMETHODIMP
1053 nsXULAppInfo::GetSubmitReports(bool* aEnabled)
1055 return CrashReporter::GetSubmitReports(aEnabled);
1058 NS_IMETHODIMP
1059 nsXULAppInfo::SetSubmitReports(bool aEnabled)
1061 return CrashReporter::SetSubmitReports(aEnabled);
1064 #endif
1066 static const nsXULAppInfo kAppInfo;
1067 static nsresult AppInfoConstructor(nsISupports* aOuter,
1068 REFNSIID aIID, void **aResult)
1070 NS_ENSURE_NO_AGGREGATION(aOuter);
1072 return const_cast<nsXULAppInfo*>(&kAppInfo)->
1073 QueryInterface(aIID, aResult);
1076 bool gLogConsoleErrors = false;
1078 #define NS_ENSURE_TRUE_LOG(x, ret) \
1079 PR_BEGIN_MACRO \
1080 if (MOZ_UNLIKELY(!(x))) { \
1081 NS_WARNING("NS_ENSURE_TRUE(" #x ") failed"); \
1082 gLogConsoleErrors = true; \
1083 return ret; \
1085 PR_END_MACRO
1087 #define NS_ENSURE_SUCCESS_LOG(res, ret) \
1088 NS_ENSURE_TRUE_LOG(NS_SUCCEEDED(res), ret)
1091 * Because we're starting/stopping XPCOM several times in different scenarios,
1092 * this class is a stack-based critter that makes sure that XPCOM is shut down
1093 * during early returns.
1096 class ScopedXPCOMStartup
1098 public:
1099 ScopedXPCOMStartup() :
1100 mServiceManager(nullptr) { }
1101 ~ScopedXPCOMStartup();
1103 nsresult Initialize();
1104 nsresult SetWindowCreator(nsINativeAppSupport* native);
1106 static nsresult CreateAppSupport(nsISupports* aOuter, REFNSIID aIID, void** aResult);
1108 private:
1109 nsIServiceManager* mServiceManager;
1110 static nsINativeAppSupport* gNativeAppSupport;
1113 ScopedXPCOMStartup::~ScopedXPCOMStartup()
1115 NS_IF_RELEASE(gNativeAppSupport);
1117 if (mServiceManager) {
1118 #ifdef XP_MACOSX
1119 // On OS X, we need a pool to catch cocoa objects that are autoreleased
1120 // during teardown.
1121 mozilla::MacAutoreleasePool pool;
1122 #endif
1124 nsCOMPtr<nsIAppStartup> appStartup (do_GetService(NS_APPSTARTUP_CONTRACTID));
1125 if (appStartup)
1126 appStartup->DestroyHiddenWindow();
1128 gDirServiceProvider->DoShutdown();
1129 PROFILER_MARKER("Shutdown early");
1131 WriteConsoleLog();
1133 NS_ShutdownXPCOM(mServiceManager);
1134 mServiceManager = nullptr;
1138 // {95d89e3e-a169-41a3-8e56-719978e15b12}
1139 #define APPINFO_CID \
1140 { 0x95d89e3e, 0xa169, 0x41a3, { 0x8e, 0x56, 0x71, 0x99, 0x78, 0xe1, 0x5b, 0x12 } }
1142 // {0C4A446C-EE82-41f2-8D04-D366D2C7A7D4}
1143 static const nsCID kNativeAppSupportCID =
1144 { 0xc4a446c, 0xee82, 0x41f2, { 0x8d, 0x4, 0xd3, 0x66, 0xd2, 0xc7, 0xa7, 0xd4 } };
1146 // {5F5E59CE-27BC-47eb-9D1F-B09CA9049836}
1147 static const nsCID kProfileServiceCID =
1148 { 0x5f5e59ce, 0x27bc, 0x47eb, { 0x9d, 0x1f, 0xb0, 0x9c, 0xa9, 0x4, 0x98, 0x36 } };
1150 static already_AddRefed<nsIFactory>
1151 ProfileServiceFactoryConstructor(const mozilla::Module& module, const mozilla::Module::CIDEntry& entry)
1153 nsCOMPtr<nsIFactory> factory;
1154 NS_NewToolkitProfileFactory(getter_AddRefs(factory));
1155 return factory.forget();
1158 NS_DEFINE_NAMED_CID(APPINFO_CID);
1160 static const mozilla::Module::CIDEntry kXRECIDs[] = {
1161 { &kAPPINFO_CID, false, nullptr, AppInfoConstructor },
1162 { &kProfileServiceCID, false, ProfileServiceFactoryConstructor, nullptr },
1163 { &kNativeAppSupportCID, false, nullptr, ScopedXPCOMStartup::CreateAppSupport },
1164 { nullptr }
1167 static const mozilla::Module::ContractIDEntry kXREContracts[] = {
1168 { XULAPPINFO_SERVICE_CONTRACTID, &kAPPINFO_CID },
1169 { XULRUNTIME_SERVICE_CONTRACTID, &kAPPINFO_CID },
1170 #ifdef MOZ_CRASHREPORTER
1171 { NS_CRASHREPORTER_CONTRACTID, &kAPPINFO_CID },
1172 #endif
1173 { NS_PROFILESERVICE_CONTRACTID, &kProfileServiceCID },
1174 { NS_NATIVEAPPSUPPORT_CONTRACTID, &kNativeAppSupportCID },
1175 { nullptr }
1178 static const mozilla::Module kXREModule = {
1179 mozilla::Module::kVersion,
1180 kXRECIDs,
1181 kXREContracts
1184 NSMODULE_DEFN(Apprunner) = &kXREModule;
1186 nsresult
1187 ScopedXPCOMStartup::Initialize()
1189 NS_ASSERTION(gDirServiceProvider, "Should not get here!");
1191 nsresult rv;
1193 rv = NS_InitXPCOM2(&mServiceManager, gDirServiceProvider->GetAppDir(),
1194 gDirServiceProvider);
1195 if (NS_FAILED(rv)) {
1196 NS_ERROR("Couldn't start xpcom!");
1197 mServiceManager = nullptr;
1199 else {
1200 nsCOMPtr<nsIComponentRegistrar> reg =
1201 do_QueryInterface(mServiceManager);
1202 NS_ASSERTION(reg, "Service Manager doesn't QI to Registrar.");
1205 return rv;
1209 * This is a little factory class that serves as a singleton-service-factory
1210 * for the nativeappsupport object.
1212 class nsSingletonFactory MOZ_FINAL : public nsIFactory
1214 public:
1215 NS_DECL_ISUPPORTS
1216 NS_DECL_NSIFACTORY
1218 nsSingletonFactory(nsISupports* aSingleton);
1219 ~nsSingletonFactory() { }
1221 private:
1222 nsCOMPtr<nsISupports> mSingleton;
1225 nsSingletonFactory::nsSingletonFactory(nsISupports* aSingleton)
1226 : mSingleton(aSingleton)
1228 NS_ASSERTION(mSingleton, "Singleton was null!");
1231 NS_IMPL_ISUPPORTS1(nsSingletonFactory, nsIFactory)
1233 NS_IMETHODIMP
1234 nsSingletonFactory::CreateInstance(nsISupports* aOuter,
1235 const nsIID& aIID,
1236 void* *aResult)
1238 NS_ENSURE_NO_AGGREGATION(aOuter);
1240 return mSingleton->QueryInterface(aIID, aResult);
1243 NS_IMETHODIMP
1244 nsSingletonFactory::LockFactory(bool)
1246 return NS_OK;
1250 * Set our windowcreator on the WindowWatcher service.
1252 nsresult
1253 ScopedXPCOMStartup::SetWindowCreator(nsINativeAppSupport* native)
1255 nsresult rv;
1257 NS_IF_ADDREF(gNativeAppSupport = native);
1259 // Inform the chrome registry about OS accessibility
1260 nsCOMPtr<nsIToolkitChromeRegistry> cr =
1261 mozilla::services::GetToolkitChromeRegistryService();
1263 if (cr)
1264 cr->CheckForOSAccessibility();
1266 nsCOMPtr<nsIWindowCreator> creator (do_GetService(NS_APPSTARTUP_CONTRACTID));
1267 if (!creator) return NS_ERROR_UNEXPECTED;
1269 nsCOMPtr<nsIWindowWatcher> wwatch
1270 (do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv));
1271 NS_ENSURE_SUCCESS(rv, rv);
1273 return wwatch->SetWindowCreator(creator);
1276 /* static */ nsresult
1277 ScopedXPCOMStartup::CreateAppSupport(nsISupports* aOuter, REFNSIID aIID, void** aResult)
1279 if (aOuter)
1280 return NS_ERROR_NO_AGGREGATION;
1282 if (!gNativeAppSupport)
1283 return NS_ERROR_NOT_INITIALIZED;
1285 return gNativeAppSupport->QueryInterface(aIID, aResult);
1288 nsINativeAppSupport* ScopedXPCOMStartup::gNativeAppSupport;
1291 * A helper class which calls NS_LogInit/NS_LogTerm in its scope.
1293 class ScopedLogging
1295 public:
1296 ScopedLogging() { NS_LogInit(); }
1297 ~ScopedLogging() { NS_LogTerm(); }
1300 static void DumpArbitraryHelp()
1302 nsresult rv;
1304 ScopedLogging log;
1307 ScopedXPCOMStartup xpcom;
1308 xpcom.Initialize();
1310 nsCOMPtr<nsICommandLineRunner> cmdline
1311 (do_CreateInstance("@mozilla.org/toolkit/command-line;1"));
1312 if (!cmdline)
1313 return;
1315 nsCString text;
1316 rv = cmdline->GetHelpText(text);
1317 if (NS_SUCCEEDED(rv))
1318 printf("%s", text.get());
1322 // English text needs to go into a dtd file.
1323 // But when this is called we have no components etc. These strings must either be
1324 // here, or in a native resource file.
1325 static void
1326 DumpHelp()
1328 printf("Usage: %s [ options ... ] [URL]\n"
1329 " where options include:\n\n", gArgv[0]);
1331 #ifdef MOZ_X11
1332 printf("X11 options\n"
1333 " --display=DISPLAY X display to use\n"
1334 " --sync Make X calls synchronous\n");
1335 #endif
1336 #ifdef XP_UNIX
1337 printf(" --g-fatal-warnings Make all warnings fatal\n"
1338 "\n%s options\n", gAppData->name);
1339 #endif
1341 printf(" -h or -help Print this message.\n"
1342 " -v or -version Print %s version.\n"
1343 " -P <profile> Start with <profile>.\n"
1344 " -migration Start with migration wizard.\n"
1345 " -ProfileManager Start with ProfileManager.\n"
1346 " -no-remote Do not accept or send remote commands; implies -new-instance.\n"
1347 " -new-instance Open new instance, not a new window in running instance.\n"
1348 " -UILocale <locale> Start with <locale> resources as UI Locale.\n"
1349 " -safe-mode Disables extensions and themes for this session.\n", gAppData->name);
1351 #if defined(XP_WIN) || defined(XP_OS2)
1352 printf(" -console Start %s with a debugging console.\n", gAppData->name);
1353 #endif
1355 // this works, but only after the components have registered. so if you drop in a new command line handler, -help
1356 // won't not until the second run.
1357 // out of the bug, because we ship a component.reg file, it works correctly.
1358 DumpArbitraryHelp();
1361 #if defined(DEBUG) && defined(XP_WIN)
1362 #ifdef DEBUG_warren
1363 #define _CRTDBG_MAP_ALLOC
1364 #endif
1365 // Set a CRT ReportHook function to capture and format MSCRT
1366 // warnings, errors and assertions.
1367 // See http://msdn.microsoft.com/en-US/library/74kabxyx(v=VS.80).aspx
1368 #include <stdio.h>
1369 #include <crtdbg.h>
1370 #include "mozilla/mozalloc_abort.h"
1371 static int MSCRTReportHook( int aReportType, char *aMessage, int *oReturnValue)
1373 *oReturnValue = 0; // continue execution
1375 // Do not use fprintf or other functions which may allocate
1376 // memory from the heap which may be corrupted. Instead,
1377 // use fputs to output the leading portion of the message
1378 // and use mozalloc_abort to emit the remainder of the
1379 // message.
1381 switch(aReportType) {
1382 case 0:
1383 fputs("\nWARNING: CRT WARNING", stderr);
1384 fputs(aMessage, stderr);
1385 fputs("\n", stderr);
1386 break;
1387 case 1:
1388 fputs("\n###!!! ABORT: CRT ERROR ", stderr);
1389 mozalloc_abort(aMessage);
1390 break;
1391 case 2:
1392 fputs("\n###!!! ABORT: CRT ASSERT ", stderr);
1393 mozalloc_abort(aMessage);
1394 break;
1397 // do not invoke the debugger
1398 return 1;
1401 #endif
1403 static inline void
1404 DumpVersion()
1406 if (gAppData->vendor)
1407 printf("%s ", gAppData->vendor);
1408 printf("%s %s", gAppData->name, gAppData->version);
1409 if (gAppData->copyright)
1410 printf(", %s", gAppData->copyright);
1411 printf("\n");
1414 #ifdef MOZ_ENABLE_XREMOTE
1415 // use int here instead of a PR type since it will be returned
1416 // from main - just to keep types consistent
1417 static int
1418 HandleRemoteArgument(const char* remote, const char* aDesktopStartupID)
1420 nsresult rv;
1421 ArgResult ar;
1423 const char *profile = 0;
1424 nsAutoCString program(gAppData->name);
1425 ToLowerCase(program);
1426 const char *username = getenv("LOGNAME");
1428 ar = CheckArg("p", false, &profile);
1429 if (ar == ARG_BAD) {
1430 PR_fprintf(PR_STDERR, "Error: argument -p requires a profile name\n");
1431 return 1;
1434 const char *temp = nullptr;
1435 ar = CheckArg("a", false, &temp);
1436 if (ar == ARG_BAD) {
1437 PR_fprintf(PR_STDERR, "Error: argument -a requires an application name\n");
1438 return 1;
1439 } else if (ar == ARG_FOUND) {
1440 program.Assign(temp);
1443 ar = CheckArg("u", false, &username);
1444 if (ar == ARG_BAD) {
1445 PR_fprintf(PR_STDERR, "Error: argument -u requires a username\n");
1446 return 1;
1449 XRemoteClient client;
1450 rv = client.Init();
1451 if (NS_FAILED(rv)) {
1452 PR_fprintf(PR_STDERR, "Error: Failed to connect to X server.\n");
1453 return 1;
1456 nsXPIDLCString response;
1457 bool success = false;
1458 rv = client.SendCommand(program.get(), username, profile, remote,
1459 aDesktopStartupID, getter_Copies(response), &success);
1460 // did the command fail?
1461 if (NS_FAILED(rv)) {
1462 PR_fprintf(PR_STDERR, "Error: Failed to send command: %s\n",
1463 response ? response.get() : "No response included");
1464 return 1;
1467 if (!success) {
1468 PR_fprintf(PR_STDERR, "Error: No running window found\n");
1469 return 2;
1472 return 0;
1475 static RemoteResult
1476 RemoteCommandLine(const char* aDesktopStartupID)
1478 nsresult rv;
1479 ArgResult ar;
1481 nsAutoCString program(gAppData->name);
1482 ToLowerCase(program);
1483 const char *username = getenv("LOGNAME");
1485 const char *temp = nullptr;
1486 ar = CheckArg("a", true, &temp);
1487 if (ar == ARG_BAD) {
1488 PR_fprintf(PR_STDERR, "Error: argument -a requires an application name\n");
1489 return REMOTE_ARG_BAD;
1490 } else if (ar == ARG_FOUND) {
1491 program.Assign(temp);
1494 ar = CheckArg("u", true, &username);
1495 if (ar == ARG_BAD) {
1496 PR_fprintf(PR_STDERR, "Error: argument -u requires a username\n");
1497 return REMOTE_ARG_BAD;
1500 XRemoteClient client;
1501 rv = client.Init();
1502 if (NS_FAILED(rv))
1503 return REMOTE_NOT_FOUND;
1505 nsXPIDLCString response;
1506 bool success = false;
1507 rv = client.SendCommandLine(program.get(), username, nullptr,
1508 gArgc, gArgv, aDesktopStartupID,
1509 getter_Copies(response), &success);
1510 // did the command fail?
1511 if (NS_FAILED(rv) || !success)
1512 return REMOTE_NOT_FOUND;
1514 return REMOTE_FOUND;
1516 #endif // MOZ_ENABLE_XREMOTE
1518 void
1519 XRE_InitOmnijar(nsIFile* greOmni, nsIFile* appOmni)
1521 mozilla::Omnijar::Init(greOmni, appOmni);
1524 nsresult
1525 XRE_GetBinaryPath(const char* argv0, nsIFile* *aResult)
1527 return mozilla::BinaryPath::GetFile(argv0, aResult);
1530 #ifdef XP_WIN
1531 #include "nsWindowsRestart.cpp"
1532 #include <shellapi.h>
1534 typedef BOOL (WINAPI* SetProcessDEPPolicyFunc)(DWORD dwFlags);
1535 #endif
1537 #if defined(XP_OS2) && (__KLIBC__ == 0 && __KLIBC_MINOR__ >= 6) // broken kLibc
1538 // Copy the environment maintained by the C library into an ASCIIZ array
1539 // that can be used to pass it on to the OS/2 Dos* APIs (which otherwise
1540 // don't know anything about the stuff set by PR_SetEnv() or setenv()).
1541 char *createEnv()
1543 // just allocate the maximum amount (24 kB = 0x60000 bytes), to be able to
1544 // copy the existing environment
1545 char *env = (char *)calloc(0x6000, sizeof(char));
1546 if (!env) {
1547 return nullptr;
1550 // walk along the environ string array of the C library and copy
1551 // everything (that fits) into the output environment array, leaving
1552 // null bytes between the entries
1553 char *penv = env; // movable pointer to result environment ASCIIZ array
1554 int i = 0, space = 0x6000;
1555 while (environ[i] && environ[i][0]) {
1556 int len = strlen(environ[i]);
1557 if (space - len <= 0) {
1558 break;
1560 strcpy(penv, environ[i]);
1561 i++; // next environment variable
1562 penv += len + 1; // jump to after next null byte
1563 space -= len - 1; // subtract consumed length from usable space
1566 return env;
1569 // OS2LaunchChild() is there to replace _execv() which is broken in the C
1570 // runtime library that comes with GCC 3.3.5 on OS/2. It uses createEnv()
1571 // to copy the process environment and add necessary variables
1573 // returns -1 on failure and 0 on success
1574 int OS2LaunchChild(const char *aExePath, int aArgc, char **aArgv)
1576 // find total length of aArgv
1577 int len = 0;
1578 for (int i = 0; i < aArgc; i++) {
1579 len += strlen(aArgv[i]) + 1; // plus space in between
1581 len++; // leave space for null byte at end
1582 // allocate enough space for all strings and nulls,
1583 // calloc helpfully initializes to null
1584 char *args = (char *)calloc(len, sizeof(char));
1585 if (!args) {
1586 return -1;
1588 char *pargs = args; // extra pointer to after the last argument
1589 // build argument list in the format the DosStartSession() wants,
1590 // adding spaces between the arguments
1591 for (int i = 0; i < aArgc; i++, *pargs++ = ' ') {
1592 strcpy(pargs, aArgv[i]);
1593 pargs += strlen(aArgv[i]);
1595 if (aArgc > 1) {
1596 *(pargs-1) = '\0'; // replace last space
1598 *pargs = '\0';
1599 // make sure that the program is separated by null byte
1600 pargs = strchr(args, ' ');
1601 if (pargs) {
1602 *pargs = '\0';
1605 char *env = createEnv();
1607 char error[CCHMAXPATH] = { 0 };
1608 RESULTCODES crc = { 0 };
1609 ULONG rc = DosExecPgm(error, sizeof(error), EXEC_ASYNC, args, env,
1610 &crc, (PSZ)aExePath);
1611 free(args); // done with the arguments
1612 if (env) {
1613 free(env);
1615 if (rc != NO_ERROR) {
1616 return -1;
1619 return 0;
1621 #endif
1623 // If aBlankCommandLine is true, then the application will be launched with a
1624 // blank command line instead of being launched with the same command line that
1625 // it was initially started with.
1626 static nsresult LaunchChild(nsINativeAppSupport* aNative,
1627 bool aBlankCommandLine = false)
1629 aNative->Quit(); // release DDE mutex, if we're holding it
1631 // Restart this process by exec'ing it into the current process
1632 // if supported by the platform. Otherwise, use NSPR.
1634 #ifdef MOZ_JPROF
1635 // make sure JPROF doesn't think we're E10s
1636 unsetenv("JPROF_SLAVE");
1637 #endif
1639 if (aBlankCommandLine) {
1640 #if defined(MOZ_WIDGET_QT)
1641 // Remove only arguments not given to Qt
1642 gRestartArgc = gQtOnlyArgc;
1643 gRestartArgv = gQtOnlyArgv;
1644 #else
1645 gRestartArgc = 1;
1646 gRestartArgv[gRestartArgc] = nullptr;
1647 #endif
1650 SaveToEnv("MOZ_LAUNCHED_CHILD=1");
1652 #if defined(MOZ_WIDGET_ANDROID)
1653 mozilla::widget::android::GeckoAppShell::ScheduleRestart();
1654 #else
1655 #if defined(XP_MACOSX)
1656 CommandLineServiceMac::SetupMacCommandLine(gRestartArgc, gRestartArgv, true);
1657 uint32_t restartMode = 0;
1658 restartMode = gRestartMode;
1659 LaunchChildMac(gRestartArgc, gRestartArgv, restartMode);
1660 #else
1661 nsCOMPtr<nsIFile> lf;
1662 nsresult rv = XRE_GetBinaryPath(gArgv[0], getter_AddRefs(lf));
1663 if (NS_FAILED(rv))
1664 return rv;
1666 #if defined(XP_WIN)
1667 nsAutoString exePath;
1668 rv = lf->GetPath(exePath);
1669 if (NS_FAILED(rv))
1670 return rv;
1672 if (!WinLaunchChild(exePath.get(), gRestartArgc, gRestartArgv))
1673 return NS_ERROR_FAILURE;
1675 #else
1676 nsAutoCString exePath;
1677 rv = lf->GetNativePath(exePath);
1678 if (NS_FAILED(rv))
1679 return rv;
1681 #if defined(XP_OS2) && (__KLIBC__ == 0 && __KLIBC_MINOR__ >= 6)
1682 // implementation of _execv() is broken with kLibc 0.6.x and later
1683 if (OS2LaunchChild(exePath.get(), gRestartArgc, gRestartArgv) == -1)
1684 return NS_ERROR_FAILURE;
1685 #elif defined(XP_OS2)
1686 if (_execv(exePath.get(), gRestartArgv) == -1)
1687 return NS_ERROR_FAILURE;
1688 #elif defined(XP_UNIX)
1689 if (execv(exePath.get(), gRestartArgv) == -1)
1690 return NS_ERROR_FAILURE;
1691 #else
1692 PRProcess* process = PR_CreateProcess(exePath.get(), gRestartArgv,
1693 nullptr, nullptr);
1694 if (!process) return NS_ERROR_FAILURE;
1696 int32_t exitCode;
1697 PRStatus failed = PR_WaitProcess(process, &exitCode);
1698 if (failed || exitCode)
1699 return NS_ERROR_FAILURE;
1700 #endif // XP_OS2 series
1701 #endif // WP_WIN
1702 #endif // WP_MACOSX
1703 #endif // MOZ_WIDGET_ANDROID
1705 return NS_ERROR_LAUNCHED_CHILD_PROCESS;
1708 static const char kProfileProperties[] =
1709 "chrome://mozapps/locale/profile/profileSelection.properties";
1711 static nsresult
1712 ProfileLockedDialog(nsIFile* aProfileDir, nsIFile* aProfileLocalDir,
1713 nsIProfileUnlocker* aUnlocker,
1714 nsINativeAppSupport* aNative, nsIProfileLock* *aResult)
1716 nsresult rv;
1718 ScopedXPCOMStartup xpcom;
1719 rv = xpcom.Initialize();
1720 NS_ENSURE_SUCCESS(rv, rv);
1722 mozilla::Telemetry::WriteFailedProfileLock(aProfileDir);
1724 rv = xpcom.SetWindowCreator(aNative);
1725 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
1727 { //extra scoping is needed so we release these components before xpcom shutdown
1728 nsCOMPtr<nsIStringBundleService> sbs =
1729 mozilla::services::GetStringBundleService();
1730 NS_ENSURE_TRUE(sbs, NS_ERROR_FAILURE);
1732 nsCOMPtr<nsIStringBundle> sb;
1733 sbs->CreateBundle(kProfileProperties, getter_AddRefs(sb));
1734 NS_ENSURE_TRUE_LOG(sbs, NS_ERROR_FAILURE);
1736 NS_ConvertUTF8toUTF16 appName(gAppData->name);
1737 const PRUnichar* params[] = {appName.get(), appName.get()};
1739 nsXPIDLString killMessage;
1740 #ifndef XP_MACOSX
1741 static const PRUnichar 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"
1742 static const PRUnichar 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"
1743 #else
1744 static const PRUnichar 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"
1745 static const PRUnichar 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"
1746 #endif
1748 sb->FormatStringFromName(aUnlocker ? kRestartUnlocker : kRestartNoUnlocker,
1749 params, 2, getter_Copies(killMessage));
1751 nsXPIDLString killTitle;
1752 sb->FormatStringFromName(NS_LITERAL_STRING("restartTitle").get(),
1753 params, 1, getter_Copies(killTitle));
1755 if (!killMessage || !killTitle)
1756 return NS_ERROR_FAILURE;
1758 nsCOMPtr<nsIPromptService> ps
1759 (do_GetService(NS_PROMPTSERVICE_CONTRACTID));
1760 NS_ENSURE_TRUE(ps, NS_ERROR_FAILURE);
1762 if (aUnlocker) {
1763 int32_t button;
1764 #ifdef MOZ_WIDGET_ANDROID
1765 mozilla::widget::android::GeckoAppShell::KillAnyZombies();
1766 button = 1;
1767 #else
1768 const uint32_t flags =
1769 (nsIPromptService::BUTTON_TITLE_CANCEL *
1770 nsIPromptService::BUTTON_POS_0) +
1771 (nsIPromptService::BUTTON_TITLE_IS_STRING *
1772 nsIPromptService::BUTTON_POS_1) +
1773 nsIPromptService::BUTTON_POS_1_DEFAULT;
1775 bool checkState = false;
1776 rv = ps->ConfirmEx(nullptr, killTitle, killMessage, flags,
1777 killTitle, nullptr, nullptr, nullptr,
1778 &checkState, &button);
1779 NS_ENSURE_SUCCESS_LOG(rv, rv);
1780 #endif
1782 if (button == 1) {
1783 rv = aUnlocker->Unlock(nsIProfileUnlocker::FORCE_QUIT);
1784 if (NS_FAILED(rv))
1785 return rv;
1787 return NS_LockProfilePath(aProfileDir, aProfileLocalDir,
1788 nullptr, aResult);
1790 } else {
1791 #ifdef MOZ_WIDGET_ANDROID
1792 if (mozilla::widget::android::GeckoAppShell::UnlockProfile()) {
1793 return NS_LockProfilePath(aProfileDir, aProfileLocalDir,
1794 nullptr, aResult);
1796 #else
1797 rv = ps->Alert(nullptr, killTitle, killMessage);
1798 NS_ENSURE_SUCCESS_LOG(rv, rv);
1799 #endif
1802 return NS_ERROR_ABORT;
1807 static nsresult
1808 ProfileMissingDialog(nsINativeAppSupport* aNative)
1810 nsresult rv;
1812 ScopedXPCOMStartup xpcom;
1813 rv = xpcom.Initialize();
1814 NS_ENSURE_SUCCESS(rv, rv);
1816 rv = xpcom.SetWindowCreator(aNative);
1817 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
1819 { //extra scoping is needed so we release these components before xpcom shutdown
1820 nsCOMPtr<nsIStringBundleService> sbs =
1821 mozilla::services::GetStringBundleService();
1822 NS_ENSURE_TRUE(sbs, NS_ERROR_FAILURE);
1824 nsCOMPtr<nsIStringBundle> sb;
1825 sbs->CreateBundle(kProfileProperties, getter_AddRefs(sb));
1826 NS_ENSURE_TRUE_LOG(sbs, NS_ERROR_FAILURE);
1828 NS_ConvertUTF8toUTF16 appName(gAppData->name);
1829 const PRUnichar* params[] = {appName.get(), appName.get()};
1831 nsXPIDLString missingMessage;
1833 // profileMissing
1834 static const PRUnichar kMissing[] = {'p','r','o','f','i','l','e','M','i','s','s','i','n','g','\0'};
1835 sb->FormatStringFromName(kMissing, params, 2, getter_Copies(missingMessage));
1837 nsXPIDLString missingTitle;
1838 sb->FormatStringFromName(NS_LITERAL_STRING("profileMissingTitle").get(),
1839 params, 1, getter_Copies(missingTitle));
1841 if (missingMessage && missingTitle) {
1842 nsCOMPtr<nsIPromptService> ps
1843 (do_GetService(NS_PROMPTSERVICE_CONTRACTID));
1844 NS_ENSURE_TRUE(ps, NS_ERROR_FAILURE);
1846 ps->Alert(nullptr, missingTitle, missingMessage);
1849 return NS_ERROR_ABORT;
1853 static nsresult
1854 ProfileLockedDialog(nsIToolkitProfile* aProfile, nsIProfileUnlocker* aUnlocker,
1855 nsINativeAppSupport* aNative, nsIProfileLock* *aResult)
1857 nsCOMPtr<nsIFile> profileDir;
1858 nsresult rv = aProfile->GetRootDir(getter_AddRefs(profileDir));
1859 if (NS_FAILED(rv)) return rv;
1861 bool exists;
1862 profileDir->Exists(&exists);
1863 if (!exists) {
1864 return ProfileMissingDialog(aNative);
1867 nsCOMPtr<nsIFile> profileLocalDir;
1868 rv = aProfile->GetLocalDir(getter_AddRefs(profileLocalDir));
1869 if (NS_FAILED(rv)) return rv;
1871 return ProfileLockedDialog(profileDir, profileLocalDir, aUnlocker, aNative,
1872 aResult);
1875 static const char kProfileManagerURL[] =
1876 "chrome://mozapps/content/profile/profileSelection.xul";
1878 static nsresult
1879 ShowProfileManager(nsIToolkitProfileService* aProfileSvc,
1880 nsINativeAppSupport* aNative)
1882 nsresult rv;
1884 nsCOMPtr<nsIFile> profD, profLD;
1885 PRUnichar* profileNamePtr;
1886 nsAutoCString profileName;
1889 ScopedXPCOMStartup xpcom;
1890 rv = xpcom.Initialize();
1891 NS_ENSURE_SUCCESS(rv, rv);
1893 rv = xpcom.SetWindowCreator(aNative);
1894 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
1896 #ifdef XP_MACOSX
1897 CommandLineServiceMac::SetupMacCommandLine(gRestartArgc, gRestartArgv, true);
1898 #endif
1900 #ifdef XP_WIN
1901 // we don't have to wait here because profile manager window will pump
1902 // and DDE message will be handled
1903 ProcessDDE(aNative, false);
1904 #endif
1906 { //extra scoping is needed so we release these components before xpcom shutdown
1907 nsCOMPtr<nsIWindowWatcher> windowWatcher
1908 (do_GetService(NS_WINDOWWATCHER_CONTRACTID));
1909 nsCOMPtr<nsIDialogParamBlock> ioParamBlock
1910 (do_CreateInstance(NS_DIALOGPARAMBLOCK_CONTRACTID));
1911 nsCOMPtr<nsIMutableArray> dlgArray (do_CreateInstance(NS_ARRAY_CONTRACTID));
1912 NS_ENSURE_TRUE(windowWatcher && ioParamBlock && dlgArray, NS_ERROR_FAILURE);
1914 ioParamBlock->SetObjects(dlgArray);
1916 nsCOMPtr<nsIAppStartup> appStartup
1917 (do_GetService(NS_APPSTARTUP_CONTRACTID));
1918 NS_ENSURE_TRUE(appStartup, NS_ERROR_FAILURE);
1920 nsCOMPtr<nsIDOMWindow> newWindow;
1921 rv = windowWatcher->OpenWindow(nullptr,
1922 kProfileManagerURL,
1923 "_blank",
1924 "centerscreen,chrome,modal,titlebar",
1925 ioParamBlock,
1926 getter_AddRefs(newWindow));
1928 NS_ENSURE_SUCCESS_LOG(rv, rv);
1930 aProfileSvc->Flush();
1932 int32_t dialogConfirmed;
1933 rv = ioParamBlock->GetInt(0, &dialogConfirmed);
1934 if (NS_FAILED(rv) || dialogConfirmed == 0) return NS_ERROR_ABORT;
1936 nsCOMPtr<nsIProfileLock> lock;
1937 rv = dlgArray->QueryElementAt(0, NS_GET_IID(nsIProfileLock),
1938 getter_AddRefs(lock));
1939 NS_ENSURE_SUCCESS_LOG(rv, rv);
1941 rv = lock->GetDirectory(getter_AddRefs(profD));
1942 NS_ENSURE_SUCCESS(rv, rv);
1944 rv = lock->GetLocalDirectory(getter_AddRefs(profLD));
1945 NS_ENSURE_SUCCESS(rv, rv);
1947 rv = ioParamBlock->GetString(0, &profileNamePtr);
1948 NS_ENSURE_SUCCESS(rv, rv);
1950 CopyUTF16toUTF8(profileNamePtr, profileName);
1951 NS_Free(profileNamePtr);
1953 lock->Unlock();
1957 SaveFileToEnv("XRE_PROFILE_PATH", profD);
1958 SaveFileToEnv("XRE_PROFILE_LOCAL_PATH", profLD);
1959 SaveWordToEnv("XRE_PROFILE_NAME", profileName);
1961 bool offline = false;
1962 aProfileSvc->GetStartOffline(&offline);
1963 if (offline) {
1964 SaveToEnv("XRE_START_OFFLINE=1");
1967 return LaunchChild(aNative);
1970 static nsresult
1971 GetCurrentProfileIsDefault(nsIToolkitProfileService* aProfileSvc,
1972 nsIFile* aCurrentProfileRoot, bool *aResult)
1974 nsresult rv;
1975 // Check that the profile to reset is the default since reset and the associated migration are
1976 // only supported in that case.
1977 nsCOMPtr<nsIToolkitProfile> selectedProfile;
1978 nsCOMPtr<nsIFile> selectedProfileRoot;
1979 rv = aProfileSvc->GetSelectedProfile(getter_AddRefs(selectedProfile));
1980 NS_ENSURE_SUCCESS(rv, rv);
1982 rv = selectedProfile->GetRootDir(getter_AddRefs(selectedProfileRoot));
1983 NS_ENSURE_SUCCESS(rv, rv);
1985 bool currentIsSelected;
1986 rv = aCurrentProfileRoot->Equals(selectedProfileRoot, &currentIsSelected);
1988 *aResult = currentIsSelected;
1989 return rv;
1993 * Set the currently running profile as the default/selected one.
1995 * @param aCurrentProfileRoot The root directory of the current profile.
1996 * @return an error if aCurrentProfileRoot is not found or the profile could not
1997 * be set as the default.
1999 static nsresult
2000 SetCurrentProfileAsDefault(nsIToolkitProfileService* aProfileSvc,
2001 nsIFile* aCurrentProfileRoot)
2003 NS_ENSURE_ARG_POINTER(aProfileSvc);
2005 nsCOMPtr<nsISimpleEnumerator> profiles;
2006 nsresult rv = aProfileSvc->GetProfiles(getter_AddRefs(profiles));
2007 if (NS_FAILED(rv))
2008 return rv;
2010 bool foundMatchingProfile = false;
2011 nsCOMPtr<nsIToolkitProfile> profile;
2012 rv = profiles->GetNext(getter_AddRefs(profile));
2013 while (NS_SUCCEEDED(rv)) {
2014 nsCOMPtr<nsIFile> profileRoot;
2015 profile->GetRootDir(getter_AddRefs(profileRoot));
2016 profileRoot->Equals(aCurrentProfileRoot, &foundMatchingProfile);
2017 if (foundMatchingProfile && profile) {
2018 rv = aProfileSvc->SetSelectedProfile(profile);
2019 if (NS_SUCCEEDED(rv))
2020 rv = aProfileSvc->Flush();
2021 return rv;
2023 rv = profiles->GetNext(getter_AddRefs(profile));
2025 return rv;
2028 static bool gDoMigration = false;
2029 static bool gDoProfileReset = false;
2031 // Pick a profile. We need to end up with a profile lock.
2033 // 1) check for -profile <path>
2034 // 2) check for -P <name>
2035 // 3) check for -ProfileManager
2036 // 4) use the default profile, if there is one
2037 // 5) if there are *no* profiles, set up profile-migration
2038 // 6) display the profile-manager UI
2039 static nsresult
2040 SelectProfile(nsIProfileLock* *aResult, nsIToolkitProfileService* aProfileSvc, nsINativeAppSupport* aNative,
2041 bool* aStartOffline, nsACString* aProfileName)
2043 StartupTimeline::Record(StartupTimeline::SELECT_PROFILE);
2045 nsresult rv;
2046 ArgResult ar;
2047 const char* arg;
2048 *aResult = nullptr;
2049 *aStartOffline = false;
2051 ar = CheckArg("offline", true);
2052 if (ar == ARG_BAD) {
2053 PR_fprintf(PR_STDERR, "Error: argument -offline is invalid when argument -osint is specified\n");
2054 return NS_ERROR_FAILURE;
2057 if (ar || EnvHasValue("XRE_START_OFFLINE"))
2058 *aStartOffline = true;
2060 if (EnvHasValue("MOZ_RESET_PROFILE_RESTART")) {
2061 gDoProfileReset = true;
2062 gDoMigration = true;
2063 SaveToEnv("MOZ_RESET_PROFILE_RESTART=");
2066 // reset-profile and migration args need to be checked before any profiles are chosen below.
2067 ar = CheckArg("reset-profile", true);
2068 if (ar == ARG_BAD) {
2069 PR_fprintf(PR_STDERR, "Error: argument -reset-profile is invalid when argument -osint is specified\n");
2070 return NS_ERROR_FAILURE;
2071 } else if (ar == ARG_FOUND) {
2072 gDoProfileReset = true;
2075 ar = CheckArg("migration", true);
2076 if (ar == ARG_BAD) {
2077 PR_fprintf(PR_STDERR, "Error: argument -migration is invalid when argument -osint is specified\n");
2078 return NS_ERROR_FAILURE;
2079 } else if (ar == ARG_FOUND) {
2080 gDoMigration = true;
2083 nsCOMPtr<nsIFile> lf = GetFileFromEnv("XRE_PROFILE_PATH");
2084 if (lf) {
2085 nsCOMPtr<nsIFile> localDir =
2086 GetFileFromEnv("XRE_PROFILE_LOCAL_PATH");
2087 if (!localDir) {
2088 localDir = lf;
2091 arg = PR_GetEnv("XRE_PROFILE_NAME");
2092 if (arg && *arg && aProfileName)
2093 aProfileName->Assign(nsDependentCString(arg));
2095 // Clear out flags that we handled (or should have handled!) last startup.
2096 const char *dummy;
2097 CheckArg("p", false, &dummy);
2098 CheckArg("profile", false, &dummy);
2099 CheckArg("profilemanager");
2101 if (gDoProfileReset) {
2102 // Check that the profile to reset is the default since reset and migration are only
2103 // supported in that case.
2104 bool currentIsSelected;
2105 GetCurrentProfileIsDefault(aProfileSvc, lf, &currentIsSelected);
2106 if (!currentIsSelected) {
2107 NS_WARNING("Profile reset is only supported for the default profile.");
2108 gDoProfileReset = gDoMigration = false;
2111 // If we're resetting a profile, create a new one and use it to startup.
2112 nsCOMPtr<nsIToolkitProfile> newProfile;
2113 rv = CreateResetProfile(aProfileSvc, getter_AddRefs(newProfile));
2114 if (NS_SUCCEEDED(rv)) {
2115 rv = newProfile->GetRootDir(getter_AddRefs(lf));
2116 NS_ENSURE_SUCCESS(rv, rv);
2117 SaveFileToEnv("XRE_PROFILE_PATH", lf);
2119 rv = newProfile->GetLocalDir(getter_AddRefs(localDir));
2120 NS_ENSURE_SUCCESS(rv, rv);
2121 SaveFileToEnv("XRE_PROFILE_LOCAL_PATH", localDir);
2123 rv = newProfile->GetName(*aProfileName);
2124 if (NS_FAILED(rv))
2125 aProfileName->Truncate(0);
2126 SaveWordToEnv("XRE_PROFILE_NAME", *aProfileName);
2127 } else {
2128 NS_WARNING("Profile reset failed.");
2129 gDoProfileReset = false;
2133 return NS_LockProfilePath(lf, localDir, nullptr, aResult);
2136 ar = CheckArg("profile", true, &arg);
2137 if (ar == ARG_BAD) {
2138 PR_fprintf(PR_STDERR, "Error: argument -profile requires a path\n");
2139 return NS_ERROR_FAILURE;
2141 if (ar) {
2142 if (gDoProfileReset) {
2143 NS_WARNING("Profile reset is only supported for the default profile.");
2144 gDoProfileReset = false;
2147 nsCOMPtr<nsIFile> lf;
2148 rv = XRE_GetFileFromPath(arg, getter_AddRefs(lf));
2149 NS_ENSURE_SUCCESS(rv, rv);
2151 nsCOMPtr<nsIProfileUnlocker> unlocker;
2153 // Check if the profile path exists and it's a directory.
2154 bool exists;
2155 lf->Exists(&exists);
2156 if (!exists) {
2157 rv = lf->Create(nsIFile::DIRECTORY_TYPE, 0700);
2158 NS_ENSURE_SUCCESS(rv, rv);
2161 // If a profile path is specified directory on the command line, then
2162 // assume that the temp directory is the same as the given directory.
2163 rv = NS_LockProfilePath(lf, lf, getter_AddRefs(unlocker), aResult);
2164 if (NS_SUCCEEDED(rv))
2165 return rv;
2167 return ProfileLockedDialog(lf, lf, unlocker, aNative, aResult);
2170 ar = CheckArg("createprofile", true, &arg);
2171 if (ar == ARG_BAD) {
2172 PR_fprintf(PR_STDERR, "Error: argument -createprofile requires a profile name\n");
2173 return NS_ERROR_FAILURE;
2175 if (ar) {
2176 nsCOMPtr<nsIToolkitProfile> profile;
2178 const char* delim = strchr(arg, ' ');
2179 if (delim) {
2180 nsCOMPtr<nsIFile> lf;
2181 rv = NS_NewNativeLocalFile(nsDependentCString(delim + 1),
2182 true, getter_AddRefs(lf));
2183 if (NS_FAILED(rv)) {
2184 PR_fprintf(PR_STDERR, "Error: profile path not valid.\n");
2185 return rv;
2188 // As with -profile, assume that the given path will be used for the
2189 // main profile directory.
2190 rv = aProfileSvc->CreateProfile(lf, nsDependentCSubstring(arg, delim),
2191 getter_AddRefs(profile));
2192 } else {
2193 rv = aProfileSvc->CreateProfile(nullptr, nsDependentCString(arg),
2194 getter_AddRefs(profile));
2196 // Some pathological arguments can make it this far
2197 if (NS_FAILED(rv)) {
2198 PR_fprintf(PR_STDERR, "Error creating profile.\n");
2199 return rv;
2201 rv = NS_ERROR_ABORT;
2202 aProfileSvc->Flush();
2204 // XXXben need to ensure prefs.js exists here so the tinderboxes will
2205 // not go orange.
2206 nsCOMPtr<nsIFile> prefsJSFile;
2207 profile->GetRootDir(getter_AddRefs(prefsJSFile));
2208 prefsJSFile->AppendNative(NS_LITERAL_CSTRING("prefs.js"));
2209 nsAutoCString pathStr;
2210 prefsJSFile->GetNativePath(pathStr);
2211 PR_fprintf(PR_STDERR, "Success: created profile '%s' at '%s'\n", arg, pathStr.get());
2212 bool exists;
2213 prefsJSFile->Exists(&exists);
2214 if (!exists)
2215 prefsJSFile->Create(nsIFile::NORMAL_FILE_TYPE, 0644);
2216 // XXXdarin perhaps 0600 would be better?
2218 return rv;
2221 uint32_t count;
2222 rv = aProfileSvc->GetProfileCount(&count);
2223 NS_ENSURE_SUCCESS(rv, rv);
2225 ar = CheckArg("p", false, &arg);
2226 if (ar == ARG_BAD) {
2227 ar = CheckArg("osint");
2228 if (ar == ARG_FOUND) {
2229 PR_fprintf(PR_STDERR, "Error: argument -p is invalid when argument -osint is specified\n");
2230 return NS_ERROR_FAILURE;
2232 return ShowProfileManager(aProfileSvc, aNative);
2234 if (ar) {
2235 ar = CheckArg("osint");
2236 if (ar == ARG_FOUND) {
2237 PR_fprintf(PR_STDERR, "Error: argument -p is invalid when argument -osint is specified\n");
2238 return NS_ERROR_FAILURE;
2240 nsCOMPtr<nsIToolkitProfile> profile;
2241 rv = aProfileSvc->GetProfileByName(nsDependentCString(arg),
2242 getter_AddRefs(profile));
2243 if (NS_SUCCEEDED(rv)) {
2244 if (gDoProfileReset) {
2245 NS_WARNING("Profile reset is only supported for the default profile.");
2246 gDoProfileReset = false;
2249 nsCOMPtr<nsIProfileUnlocker> unlocker;
2250 rv = profile->Lock(getter_AddRefs(unlocker), aResult);
2251 if (NS_SUCCEEDED(rv)) {
2252 if (aProfileName)
2253 aProfileName->Assign(nsDependentCString(arg));
2254 return NS_OK;
2257 return ProfileLockedDialog(profile, unlocker, aNative, aResult);
2260 return ShowProfileManager(aProfileSvc, aNative);
2263 ar = CheckArg("profilemanager", true);
2264 if (ar == ARG_BAD) {
2265 PR_fprintf(PR_STDERR, "Error: argument -profilemanager is invalid when argument -osint is specified\n");
2266 return NS_ERROR_FAILURE;
2267 } else if (ar == ARG_FOUND) {
2268 return ShowProfileManager(aProfileSvc, aNative);
2271 if (!count) {
2272 gDoMigration = true;
2273 gDoProfileReset = false;
2275 // create a default profile
2276 nsCOMPtr<nsIToolkitProfile> profile;
2277 nsresult rv = aProfileSvc->CreateProfile(nullptr, // choose a default dir for us
2278 NS_LITERAL_CSTRING("default"),
2279 getter_AddRefs(profile));
2280 if (NS_SUCCEEDED(rv)) {
2281 aProfileSvc->Flush();
2282 rv = profile->Lock(nullptr, aResult);
2283 if (NS_SUCCEEDED(rv)) {
2284 if (aProfileName)
2285 aProfileName->Assign(NS_LITERAL_CSTRING("default"));
2286 return NS_OK;
2291 bool useDefault = true;
2292 if (count > 1)
2293 aProfileSvc->GetStartWithLastProfile(&useDefault);
2295 if (useDefault) {
2296 nsCOMPtr<nsIToolkitProfile> profile;
2297 // GetSelectedProfile will auto-select the only profile if there's just one
2298 aProfileSvc->GetSelectedProfile(getter_AddRefs(profile));
2299 if (profile) {
2300 // If we're resetting a profile, create a new one and use it to startup.
2301 if (gDoProfileReset) {
2303 // Check that the source profile is not in use by temporarily acquiring its lock.
2304 nsIProfileLock* tempProfileLock;
2305 nsCOMPtr<nsIProfileUnlocker> unlocker;
2306 rv = profile->Lock(getter_AddRefs(unlocker), &tempProfileLock);
2307 if (NS_FAILED(rv))
2308 return ProfileLockedDialog(profile, unlocker, aNative, &tempProfileLock);
2311 nsCOMPtr<nsIToolkitProfile> newProfile;
2312 rv = CreateResetProfile(aProfileSvc, getter_AddRefs(newProfile));
2313 if (NS_SUCCEEDED(rv))
2314 profile = newProfile;
2315 else
2316 gDoProfileReset = false;
2319 // If you close Firefox and very quickly reopen it, the old Firefox may
2320 // still be closing down. Rather than immediately showing the
2321 // "Firefox is running but is not responding" message, we spend a few
2322 // seconds retrying first.
2324 static const int kLockRetrySeconds = 5;
2325 static const int kLockRetrySleepMS = 100;
2327 nsCOMPtr<nsIProfileUnlocker> unlocker;
2328 const TimeStamp start = TimeStamp::Now();
2329 do {
2330 rv = profile->Lock(getter_AddRefs(unlocker), aResult);
2331 if (NS_SUCCEEDED(rv)) {
2332 StartupTimeline::Record(StartupTimeline::AFTER_PROFILE_LOCKED);
2333 // Try to grab the profile name.
2334 if (aProfileName) {
2335 rv = profile->GetName(*aProfileName);
2336 if (NS_FAILED(rv))
2337 aProfileName->Truncate(0);
2339 return NS_OK;
2341 PR_Sleep(kLockRetrySleepMS);
2342 } while (TimeStamp::Now() - start < TimeDuration::FromSeconds(kLockRetrySeconds));
2344 return ProfileLockedDialog(profile, unlocker, aNative, aResult);
2348 return ShowProfileManager(aProfileSvc, aNative);
2351 /**
2352 * Checks the compatibility.ini file to see if we have updated our application
2353 * or otherwise invalidated our caches. If the application has been updated,
2354 * we return false; otherwise, we return true. We also write the status
2355 * of the caches (valid/invalid) into the return param aCachesOK. The aCachesOK
2356 * is always invalid if the application has been updated.
2358 static bool
2359 CheckCompatibility(nsIFile* aProfileDir, const nsCString& aVersion,
2360 const nsCString& aOSABI, nsIFile* aXULRunnerDir,
2361 nsIFile* aAppDir, nsIFile* aFlagFile,
2362 bool* aCachesOK)
2364 *aCachesOK = false;
2365 nsCOMPtr<nsIFile> file;
2366 aProfileDir->Clone(getter_AddRefs(file));
2367 if (!file)
2368 return false;
2369 file->AppendNative(FILE_COMPATIBILITY_INFO);
2371 nsINIParser parser;
2372 nsresult rv = parser.Init(file);
2373 if (NS_FAILED(rv))
2374 return false;
2376 nsAutoCString buf;
2377 rv = parser.GetString("Compatibility", "LastVersion", buf);
2378 if (NS_FAILED(rv) || !aVersion.Equals(buf))
2379 return false;
2381 rv = parser.GetString("Compatibility", "LastOSABI", buf);
2382 if (NS_FAILED(rv) || !aOSABI.Equals(buf))
2383 return false;
2385 rv = parser.GetString("Compatibility", "LastPlatformDir", buf);
2386 if (NS_FAILED(rv))
2387 return false;
2389 nsCOMPtr<nsIFile> lf;
2390 rv = NS_NewNativeLocalFile(buf, false,
2391 getter_AddRefs(lf));
2392 if (NS_FAILED(rv))
2393 return false;
2395 bool eq;
2396 rv = lf->Equals(aXULRunnerDir, &eq);
2397 if (NS_FAILED(rv) || !eq)
2398 return false;
2400 if (aAppDir) {
2401 rv = parser.GetString("Compatibility", "LastAppDir", buf);
2402 if (NS_FAILED(rv))
2403 return false;
2405 rv = NS_NewNativeLocalFile(buf, false,
2406 getter_AddRefs(lf));
2407 if (NS_FAILED(rv))
2408 return false;
2410 rv = lf->Equals(aAppDir, &eq);
2411 if (NS_FAILED(rv) || !eq)
2412 return false;
2415 // If we see this flag, caches are invalid.
2416 rv = parser.GetString("Compatibility", "InvalidateCaches", buf);
2417 *aCachesOK = (NS_FAILED(rv) || !buf.EqualsLiteral("1"));
2419 bool purgeCaches = false;
2420 if (aFlagFile) {
2421 aFlagFile->Exists(&purgeCaches);
2424 *aCachesOK = !purgeCaches && *aCachesOK;
2425 return true;
2428 static void BuildVersion(nsCString &aBuf)
2430 aBuf.Assign(gAppData->version);
2431 aBuf.Append('_');
2432 aBuf.Append(gAppData->buildID);
2433 aBuf.Append('/');
2434 aBuf.Append(gToolkitBuildID);
2437 static void
2438 WriteVersion(nsIFile* aProfileDir, const nsCString& aVersion,
2439 const nsCString& aOSABI, nsIFile* aXULRunnerDir,
2440 nsIFile* aAppDir, bool invalidateCache)
2442 nsCOMPtr<nsIFile> file;
2443 aProfileDir->Clone(getter_AddRefs(file));
2444 if (!file)
2445 return;
2446 file->AppendNative(FILE_COMPATIBILITY_INFO);
2448 nsAutoCString platformDir;
2449 aXULRunnerDir->GetNativePath(platformDir);
2451 nsAutoCString appDir;
2452 if (aAppDir)
2453 aAppDir->GetNativePath(appDir);
2455 PRFileDesc *fd = nullptr;
2456 file->OpenNSPRFileDesc(PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, 0600, &fd);
2457 if (!fd) {
2458 NS_ERROR("could not create output stream");
2459 return;
2462 static const char kHeader[] = "[Compatibility]" NS_LINEBREAK
2463 "LastVersion=";
2465 PR_Write(fd, kHeader, sizeof(kHeader) - 1);
2466 PR_Write(fd, aVersion.get(), aVersion.Length());
2468 static const char kOSABIHeader[] = NS_LINEBREAK "LastOSABI=";
2469 PR_Write(fd, kOSABIHeader, sizeof(kOSABIHeader) - 1);
2470 PR_Write(fd, aOSABI.get(), aOSABI.Length());
2472 static const char kPlatformDirHeader[] = NS_LINEBREAK "LastPlatformDir=";
2474 PR_Write(fd, kPlatformDirHeader, sizeof(kPlatformDirHeader) - 1);
2475 PR_Write(fd, platformDir.get(), platformDir.Length());
2477 static const char kAppDirHeader[] = NS_LINEBREAK "LastAppDir=";
2478 if (aAppDir) {
2479 PR_Write(fd, kAppDirHeader, sizeof(kAppDirHeader) - 1);
2480 PR_Write(fd, appDir.get(), appDir.Length());
2483 static const char kInvalidationHeader[] = "InvalidateCaches=1" NS_LINEBREAK;
2484 if (invalidateCache)
2485 PR_Write(fd, kInvalidationHeader, sizeof(kInvalidationHeader) - 1);
2487 static const char kNL[] = NS_LINEBREAK;
2488 PR_Write(fd, kNL, sizeof(kNL) - 1);
2490 PR_Close(fd);
2494 * Returns true if the startup cache file was successfully removed.
2495 * Returns false if file->Clone fails at any point (OOM) or if unable
2496 * to remove the startup cache file. Note in particular the return value
2497 * is unaffected by a failure to remove extensions.ini
2499 static bool
2500 RemoveComponentRegistries(nsIFile* aProfileDir, nsIFile* aLocalProfileDir,
2501 bool aRemoveEMFiles)
2503 nsCOMPtr<nsIFile> file;
2504 aProfileDir->Clone(getter_AddRefs(file));
2505 if (!file)
2506 return false;
2508 if (aRemoveEMFiles) {
2509 file->SetNativeLeafName(NS_LITERAL_CSTRING("extensions.ini"));
2510 file->Remove(false);
2513 aLocalProfileDir->Clone(getter_AddRefs(file));
2514 if (!file)
2515 return false;
2517 #if defined(XP_UNIX) || defined(XP_BEOS)
2518 #define PLATFORM_FASL_SUFFIX ".mfasl"
2519 #elif defined(XP_WIN) || defined(XP_OS2)
2520 #define PLATFORM_FASL_SUFFIX ".mfl"
2521 #endif
2523 file->AppendNative(NS_LITERAL_CSTRING("XUL" PLATFORM_FASL_SUFFIX));
2524 file->Remove(false);
2526 file->SetNativeLeafName(NS_LITERAL_CSTRING("XPC" PLATFORM_FASL_SUFFIX));
2527 file->Remove(false);
2529 file->SetNativeLeafName(NS_LITERAL_CSTRING("startupCache"));
2530 nsresult rv = file->Remove(true);
2531 return NS_SUCCEEDED(rv) || rv == NS_ERROR_FILE_TARGET_DOES_NOT_EXIST;
2534 // To support application initiated restart via nsIAppStartup.quit, we
2535 // need to save various environment variables, and then restore them
2536 // before re-launching the application.
2538 static struct SavedVar {
2539 const char *name;
2540 char *value;
2541 } gSavedVars[] = {
2542 {"XUL_APP_FILE", nullptr}
2545 static void SaveStateForAppInitiatedRestart()
2547 for (size_t i = 0; i < ArrayLength(gSavedVars); ++i) {
2548 const char *s = PR_GetEnv(gSavedVars[i].name);
2549 if (s)
2550 gSavedVars[i].value = PR_smprintf("%s=%s", gSavedVars[i].name, s);
2554 static void RestoreStateForAppInitiatedRestart()
2556 for (size_t i = 0; i < ArrayLength(gSavedVars); ++i) {
2557 if (gSavedVars[i].value)
2558 PR_SetEnv(gSavedVars[i].value);
2562 #ifdef MOZ_CRASHREPORTER
2563 // When we first initialize the crash reporter we don't have a profile,
2564 // so we set the minidump path to $TEMP. Once we have a profile,
2565 // we set it to $PROFILE/minidumps, creating the directory
2566 // if needed.
2567 static void MakeOrSetMinidumpPath(nsIFile* profD)
2569 nsCOMPtr<nsIFile> dumpD;
2570 profD->Clone(getter_AddRefs(dumpD));
2572 if(dumpD) {
2573 bool fileExists;
2574 //XXX: do some more error checking here
2575 dumpD->Append(NS_LITERAL_STRING("minidumps"));
2576 dumpD->Exists(&fileExists);
2577 if(!fileExists) {
2578 dumpD->Create(nsIFile::DIRECTORY_TYPE, 0700);
2581 nsAutoString pathStr;
2582 if(NS_SUCCEEDED(dumpD->GetPath(pathStr)))
2583 CrashReporter::SetMinidumpPath(pathStr);
2586 #endif
2588 const nsXREAppData* gAppData = nullptr;
2590 #if defined(XP_OS2)
2591 // because we use early returns, we use a stack-based helper to un-set the OS2 FP handler
2592 class ScopedFPHandler {
2593 private:
2594 EXCEPTIONREGISTRATIONRECORD excpreg;
2596 public:
2597 ScopedFPHandler() { PR_OS2_SetFloatExcpHandler(&excpreg); }
2598 ~ScopedFPHandler() { PR_OS2_UnsetFloatExcpHandler(&excpreg); }
2600 #endif
2602 #ifdef MOZ_WIDGET_GTK
2603 #include "prlink.h"
2604 typedef void (*_g_set_application_name_fn)(const gchar *application_name);
2605 typedef void (*_gtk_window_set_auto_startup_notification_fn)(gboolean setting);
2607 static PRFuncPtr FindFunction(const char* aName)
2609 PRLibrary *lib = nullptr;
2610 PRFuncPtr result = PR_FindFunctionSymbolAndLibrary(aName, &lib);
2611 // Since the library was already loaded, we can safely unload it here.
2612 if (lib) {
2613 PR_UnloadLibrary(lib);
2615 return result;
2618 static void MOZ_gdk_display_close(GdkDisplay *display)
2620 // XXX wallpaper for bug 417163: don't close the Display if we're using the
2621 // Qt theme because we crash (in Qt code) when using jemalloc.
2622 bool theme_is_qt = false;
2623 GtkSettings* settings =
2624 gtk_settings_get_for_screen(gdk_display_get_default_screen(display));
2625 gchar *theme_name;
2626 g_object_get(settings, "gtk-theme-name", &theme_name, nullptr);
2627 if (theme_name) {
2628 theme_is_qt = strcmp(theme_name, "Qt") == 0;
2629 if (theme_is_qt)
2630 NS_WARNING("wallpaper bug 417163 for Qt theme");
2631 g_free(theme_name);
2634 #if CLEANUP_MEMORY
2635 // Get a (new) Pango context that holds a reference to the fontmap that
2636 // GTK has been using. gdk_pango_context_get() must be called while GTK
2637 // has a default display.
2638 PangoContext *pangoContext = gdk_pango_context_get();
2639 #endif
2641 bool buggyCairoShutdown = cairo_version() < CAIRO_VERSION_ENCODE(1, 4, 0);
2643 if (!buggyCairoShutdown) {
2644 // We should shut down GDK before we shut down libraries it depends on
2645 // like Pango and cairo. But if cairo shutdown is buggy, we should
2646 // shut down cairo first otherwise it may crash because of dangling
2647 // references to Display objects (see bug 469831).
2648 if (!theme_is_qt)
2649 gdk_display_close(display);
2652 #if CLEANUP_MEMORY
2653 // This doesn't take a reference.
2654 PangoFontMap *fontmap = pango_context_get_font_map(pangoContext);
2655 // Do some shutdown of the fontmap, which releases the fonts, clearing a
2656 // bunch of circular references from the fontmap through the fonts back to
2657 // itself. The shutdown that this does is much less than what's done by
2658 // the fontmap's finalize, though.
2659 if (PANGO_IS_FC_FONT_MAP(fontmap))
2660 pango_fc_font_map_shutdown(PANGO_FC_FONT_MAP(fontmap));
2661 g_object_unref(pangoContext);
2662 // PangoCairo still holds a reference to the fontmap.
2663 // Now that we have finished with GTK and Pango, we could unref fontmap,
2664 // which would allow us to call FcFini, but removing what is really
2665 // Pango's ref feels a bit evil. Pango-1.22 will have support for
2666 // pango_cairo_font_map_set_default(nullptr), which would release the
2667 // reference on the old fontmap.
2669 // cairo_debug_reset_static_data() is prototyped through cairo.h included
2670 // by gtk.h.
2671 #ifdef cairo_debug_reset_static_data
2672 #error "Looks like we're including Mozilla's cairo instead of system cairo"
2673 #endif
2674 cairo_debug_reset_static_data();
2675 #endif // CLEANUP_MEMORY
2677 if (buggyCairoShutdown) {
2678 if (!theme_is_qt)
2679 gdk_display_close(display);
2682 #endif // MOZ_WIDGET_GTK2
2684 /**
2685 * NSPR will search for the "nspr_use_zone_allocator" symbol throughout
2686 * the process and use it to determine whether the application defines its own
2687 * memory allocator or not.
2689 * Since most applications (e.g. Firefox and Thunderbird) don't use any special
2690 * allocators and therefore don't define this symbol, NSPR must search the
2691 * entire process, which reduces startup performance.
2693 * By defining the symbol here, we can avoid the wasted lookup and hopefully
2694 * improve startup performance.
2696 NS_VISIBILITY_DEFAULT PRBool nspr_use_zone_allocator = PR_FALSE;
2698 #ifdef CAIRO_HAS_DWRITE_FONT
2700 #include <dwrite.h>
2702 typedef HRESULT (WINAPI*DWriteCreateFactoryFunc)(
2703 DWRITE_FACTORY_TYPE factoryType,
2704 REFIID iid,
2705 IUnknown **factory
2708 #ifdef DEBUG_DWRITE_STARTUP
2710 #define LOGREGISTRY(msg) LogRegistryEvent(msg)
2712 // for use when monitoring process
2713 static void LogRegistryEvent(const wchar_t *msg)
2715 HKEY dummyKey;
2716 HRESULT hr;
2717 wchar_t buf[512];
2719 wsprintf(buf, L" log %s", msg);
2720 hr = RegOpenKeyEx(HKEY_LOCAL_MACHINE, buf, 0, KEY_READ, &dummyKey);
2721 if (SUCCEEDED(hr)) {
2722 RegCloseKey(dummyKey);
2725 #else
2727 #define LOGREGISTRY(msg)
2729 #endif
2731 static DWORD InitDwriteBG(LPVOID lpdwThreadParam)
2733 SetThreadPriority(GetCurrentThread(), THREAD_MODE_BACKGROUND_BEGIN);
2734 LOGREGISTRY(L"loading dwrite.dll");
2735 HMODULE dwdll = LoadLibraryW(L"dwrite.dll");
2736 if (dwdll) {
2737 DWriteCreateFactoryFunc createDWriteFactory = (DWriteCreateFactoryFunc)
2738 GetProcAddress(dwdll, "DWriteCreateFactory");
2739 if (createDWriteFactory) {
2740 LOGREGISTRY(L"creating dwrite factory");
2741 IDWriteFactory *factory;
2742 HRESULT hr = createDWriteFactory(
2743 DWRITE_FACTORY_TYPE_SHARED,
2744 __uuidof(IDWriteFactory),
2745 reinterpret_cast<IUnknown**>(&factory));
2746 if (SUCCEEDED(hr)) {
2747 LOGREGISTRY(L"dwrite factory done");
2748 factory->Release();
2749 LOGREGISTRY(L"freed factory");
2750 } else {
2751 LOGREGISTRY(L"failed to create factory");
2755 SetThreadPriority(GetCurrentThread(), THREAD_MODE_BACKGROUND_END);
2756 return 0;
2758 #endif
2760 #ifdef USE_GLX_TEST
2761 bool fire_glxtest_process();
2762 #endif
2764 #include "GeckoProfiler.h"
2766 // Encapsulates startup and shutdown state for XRE_main
2767 class XREMain
2769 public:
2770 XREMain() :
2771 mScopedXPCom(nullptr)
2772 , mAppData(nullptr)
2773 , mStartOffline(false)
2774 , mShuttingDown(false)
2775 #ifdef MOZ_ENABLE_XREMOTE
2776 , mDisableRemote(false)
2777 #endif
2778 #if defined(MOZ_WIDGET_GTK)
2779 , mGdkDisplay(nullptr)
2780 #endif
2783 ~XREMain() {
2784 if (mAppData) {
2785 delete mAppData;
2787 if (mScopedXPCom) {
2788 NS_WARNING("Scoped xpcom should have been deleted!");
2789 delete mScopedXPCom;
2793 int XRE_main(int argc, char* argv[], const nsXREAppData* aAppData);
2794 int XRE_mainInit(bool* aExitFlag);
2795 int XRE_mainStartup(bool* aExitFlag);
2796 nsresult XRE_mainRun();
2798 nsCOMPtr<nsINativeAppSupport> mNativeApp;
2799 nsCOMPtr<nsIToolkitProfileService> mProfileSvc;
2800 nsCOMPtr<nsIFile> mProfD;
2801 nsCOMPtr<nsIFile> mProfLD;
2802 nsCOMPtr<nsIProfileLock> mProfileLock;
2803 #ifdef MOZ_ENABLE_XREMOTE
2804 nsCOMPtr<nsIRemoteService> mRemoteService;
2805 #endif
2807 ScopedXPCOMStartup* mScopedXPCom;
2808 ScopedAppData* mAppData;
2809 nsXREDirProvider mDirProvider;
2810 nsAutoCString mProfileName;
2811 nsAutoCString mDesktopStartupID;
2813 bool mStartOffline;
2814 bool mShuttingDown;
2815 #ifdef MOZ_ENABLE_XREMOTE
2816 bool mDisableRemote;
2817 #endif
2819 #if defined(MOZ_WIDGET_GTK)
2820 GdkDisplay* mGdkDisplay;
2821 #endif
2825 * XRE_mainInit - Initial setup and command line parameter processing.
2826 * Main() will exit early if either return value != 0 or if aExitFlag is
2827 * true.
2830 XREMain::XRE_mainInit(bool* aExitFlag)
2832 if (!aExitFlag)
2833 return 1;
2834 *aExitFlag = false;
2836 StartupTimeline::Record(StartupTimeline::MAIN);
2838 nsresult rv;
2839 ArgResult ar;
2841 #ifdef DEBUG
2842 if (PR_GetEnv("XRE_MAIN_BREAK"))
2843 NS_BREAK();
2844 #endif
2846 #ifdef USE_GLX_TEST
2847 // bug 639842 - it's very important to fire this process BEFORE we set up
2848 // error handling. indeed, this process is expected to be crashy, and we
2849 // don't want the user to see its crashes. That's the whole reason for
2850 // doing this in a separate process.
2851 if (fire_glxtest_process()) {
2852 *aExitFlag = true;
2853 return 0;
2855 #endif
2857 SetupErrorHandling(gArgv[0]);
2859 #ifdef CAIRO_HAS_DWRITE_FONT
2861 // Bug 602792 - when DWriteCreateFactory is called the dwrite client dll
2862 // starts the FntCache service if it isn't already running (it's set
2863 // to manual startup by default in Windows 7 RTM). Subsequent DirectWrite
2864 // calls cause the IDWriteFactory object to communicate with the FntCache
2865 // service with a timeout; if there's no response after the timeout, the
2866 // DirectWrite client library will assume the service isn't around and do
2867 // manual font file I/O on _all_ system fonts. To avoid this, load the
2868 // dwrite library and create a factory as early as possible so that the
2869 // FntCache service is ready by the time it's needed.
2871 if (IsVistaOrLater()) {
2872 CreateThread(nullptr, 0, (LPTHREAD_START_ROUTINE)&InitDwriteBG,
2873 nullptr, 0, nullptr);
2876 #endif
2878 #ifdef XP_UNIX
2879 const char *home = PR_GetEnv("HOME");
2880 if (!home || !*home) {
2881 struct passwd *pw = getpwuid(geteuid());
2882 if (!pw || !pw->pw_dir) {
2883 Output(true, "Could not determine HOME directory");
2884 return 1;
2886 SaveWordToEnv("HOME", nsDependentCString(pw->pw_dir));
2888 #endif
2890 #ifdef MOZ_ACCESSIBILITY_ATK
2891 // Reset GTK_MODULES, strip atk-bridge if exists
2892 // Mozilla will load libatk-bridge.so later if necessary
2893 const char* gtkModules = PR_GetEnv("GTK_MODULES");
2894 if (gtkModules && *gtkModules) {
2895 nsCString gtkModulesStr(gtkModules);
2896 gtkModulesStr.ReplaceSubstring("atk-bridge", "");
2897 char* expr = PR_smprintf("GTK_MODULES=%s", gtkModulesStr.get());
2898 if (expr)
2899 PR_SetEnv(expr);
2900 // We intentionally leak |expr| here since it is required by PR_SetEnv.
2903 // Suppress atk-bridge init at startup, it works after GNOME 2.24.2
2904 SaveToEnv("NO_AT_BRIDGE=1");
2905 #endif
2907 // Check for application.ini overrides
2908 const char* override = nullptr;
2909 ar = CheckArg("override", true, &override);
2910 if (ar == ARG_BAD) {
2911 Output(true, "Incorrect number of arguments passed to -override");
2912 return 1;
2914 else if (ar == ARG_FOUND) {
2915 nsCOMPtr<nsIFile> overrideLF;
2916 rv = XRE_GetFileFromPath(override, getter_AddRefs(overrideLF));
2917 if (NS_FAILED(rv)) {
2918 Output(true, "Error: unrecognized override.ini path.\n");
2919 return 1;
2922 rv = XRE_ParseAppData(overrideLF, mAppData);
2923 if (NS_FAILED(rv)) {
2924 Output(true, "Couldn't read override.ini");
2925 return 1;
2929 // Check sanity and correctness of app data.
2931 if (!mAppData->name) {
2932 Output(true, "Error: App:Name not specified in application.ini\n");
2933 return 1;
2935 if (!mAppData->buildID) {
2936 Output(true, "Error: App:BuildID not specified in application.ini\n");
2937 return 1;
2940 // XXX Originally ScopedLogging was here? Now it's in XRE_main above
2941 // XRE_mainInit.
2943 if (!mAppData->xreDirectory) {
2944 nsCOMPtr<nsIFile> lf;
2945 rv = XRE_GetBinaryPath(gArgv[0], getter_AddRefs(lf));
2946 if (NS_FAILED(rv))
2947 return 2;
2949 nsCOMPtr<nsIFile> greDir;
2950 rv = lf->GetParent(getter_AddRefs(greDir));
2951 if (NS_FAILED(rv))
2952 return 2;
2954 rv = CallQueryInterface(greDir, &mAppData->xreDirectory);
2955 if (NS_FAILED(rv))
2956 return 2;
2959 if (!mAppData->directory) {
2960 NS_IF_ADDREF(mAppData->directory = mAppData->xreDirectory);
2963 if (mAppData->size > offsetof(nsXREAppData, minVersion)) {
2964 if (!mAppData->minVersion) {
2965 Output(true, "Error: Gecko:MinVersion not specified in application.ini\n");
2966 return 1;
2969 if (!mAppData->maxVersion) {
2970 // If no maxVersion is specified, we assume the app is only compatible
2971 // with the initial preview release. Do not increment this number ever!
2972 SetAllocatedString(mAppData->maxVersion, "1.*");
2975 if (mozilla::Version(mAppData->minVersion) > gToolkitVersion ||
2976 mozilla::Version(mAppData->maxVersion) < gToolkitVersion) {
2977 Output(true, "Error: Platform version '%s' is not compatible with\n"
2978 "minVersion >= %s\nmaxVersion <= %s\n",
2979 gToolkitVersion,
2980 mAppData->minVersion, mAppData->maxVersion);
2981 return 1;
2985 rv = mDirProvider.Initialize(mAppData->directory, mAppData->xreDirectory);
2986 if (NS_FAILED(rv))
2987 return 1;
2989 #ifdef MOZ_CRASHREPORTER
2990 if (EnvHasValue("MOZ_CRASHREPORTER")) {
2991 mAppData->flags |= NS_XRE_ENABLE_CRASH_REPORTER;
2994 if ((mAppData->flags & NS_XRE_ENABLE_CRASH_REPORTER) &&
2995 NS_SUCCEEDED(
2996 CrashReporter::SetExceptionHandler(mAppData->xreDirectory))) {
2997 if (mAppData->crashReporterURL)
2998 CrashReporter::SetServerURL(nsDependentCString(mAppData->crashReporterURL));
3000 // pass some basic info from the app data
3001 if (mAppData->vendor)
3002 CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("Vendor"),
3003 nsDependentCString(mAppData->vendor));
3004 if (mAppData->name)
3005 CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("ProductName"),
3006 nsDependentCString(mAppData->name));
3007 if (mAppData->ID)
3008 CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("ProductID"),
3009 nsDependentCString(mAppData->ID));
3010 if (mAppData->version)
3011 CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("Version"),
3012 nsDependentCString(mAppData->version));
3013 if (mAppData->buildID)
3014 CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("BuildID"),
3015 nsDependentCString(mAppData->buildID));
3017 nsDependentCString releaseChannel(NS_STRINGIFY(MOZ_UPDATE_CHANNEL));
3018 CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("ReleaseChannel"),
3019 releaseChannel);
3020 #ifdef MOZ_LINKER
3021 CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("CrashAddressLikelyWrong"),
3022 IsSignalHandlingBroken() ? NS_LITERAL_CSTRING("1")
3023 : NS_LITERAL_CSTRING("0"));
3024 #endif
3025 CrashReporter::SetRestartArgs(gArgc, gArgv);
3027 // annotate other data (user id etc)
3028 nsCOMPtr<nsIFile> userAppDataDir;
3029 if (NS_SUCCEEDED(mDirProvider.GetUserAppDataDirectory(
3030 getter_AddRefs(userAppDataDir)))) {
3031 CrashReporter::SetupExtraData(userAppDataDir,
3032 nsDependentCString(mAppData->buildID));
3034 // see if we have a crashreporter-override.ini in the application directory
3035 nsCOMPtr<nsIFile> overrideini;
3036 bool exists;
3037 if (NS_SUCCEEDED(mDirProvider.GetAppDir()->Clone(getter_AddRefs(overrideini))) &&
3038 NS_SUCCEEDED(overrideini->AppendNative(NS_LITERAL_CSTRING("crashreporter-override.ini"))) &&
3039 NS_SUCCEEDED(overrideini->Exists(&exists)) &&
3040 exists) {
3041 #ifdef XP_WIN
3042 nsAutoString overridePathW;
3043 overrideini->GetPath(overridePathW);
3044 NS_ConvertUTF16toUTF8 overridePath(overridePathW);
3045 #else
3046 nsAutoCString overridePath;
3047 overrideini->GetNativePath(overridePath);
3048 #endif
3050 SaveWordToEnv("MOZ_CRASHREPORTER_STRINGS_OVERRIDE", overridePath);
3054 #endif
3056 #ifdef XP_MACOSX
3057 if (EnvHasValue("MOZ_LAUNCHED_CHILD")) {
3058 // This is needed, on relaunch, to force the OS to use the "Cocoa Dock
3059 // API". Otherwise the call to ReceiveNextEvent() below will make it
3060 // use the "Carbon Dock API". For more info see bmo bug 377166.
3061 EnsureUseCocoaDockAPI();
3063 // When the app relaunches, the original process exits. This causes
3064 // the dock tile to stop bouncing, lose the "running" triangle, and
3065 // if the tile does not permanently reside in the Dock, even disappear.
3066 // This can be confusing to the user, who is expecting the app to launch.
3067 // Calling ReceiveNextEvent without requesting any event is enough to
3068 // cause a dock tile for the child process to appear.
3069 const EventTypeSpec kFakeEventList[] = { { INT_MAX, INT_MAX } };
3070 EventRef event;
3071 ::ReceiveNextEvent(GetEventTypeCount(kFakeEventList), kFakeEventList,
3072 kEventDurationNoWait, false, &event);
3075 if (CheckArg("foreground")) {
3076 // The original process communicates that it was in the foreground by
3077 // adding this argument. This new process, which is taking over for
3078 // the old one, should make itself the active application.
3079 ProcessSerialNumber psn;
3080 if (::GetCurrentProcess(&psn) == noErr)
3081 ::SetFrontProcess(&psn);
3083 #endif
3085 SaveToEnv("MOZ_LAUNCHED_CHILD=");
3087 gRestartArgc = gArgc;
3088 gRestartArgv = (char**) malloc(sizeof(char*) * (gArgc + 1 + (override ? 2 : 0)));
3089 if (!gRestartArgv) {
3090 return 1;
3093 int i;
3094 for (i = 0; i < gArgc; ++i) {
3095 gRestartArgv[i] = gArgv[i];
3098 // Add the -override argument back (it is removed automatically be CheckArg) if there is one
3099 if (override) {
3100 gRestartArgv[gRestartArgc++] = const_cast<char*>("-override");
3101 gRestartArgv[gRestartArgc++] = const_cast<char*>(override);
3104 gRestartArgv[gRestartArgc] = nullptr;
3107 #if defined(XP_OS2)
3108 bool StartOS2App(int aArgc, char **aArgv);
3109 if (!StartOS2App(gArgc, gArgv))
3110 return 1;
3111 ScopedFPHandler handler;
3112 #endif /* XP_OS2 */
3114 if (EnvHasValue("MOZ_SAFE_MODE_RESTART")) {
3115 gSafeMode = true;
3116 // unset the env variable
3117 SaveToEnv("MOZ_SAFE_MODE_RESTART=");
3120 ar = CheckArg("safe-mode", true);
3121 if (ar == ARG_BAD) {
3122 PR_fprintf(PR_STDERR, "Error: argument -safe-mode is invalid when argument -osint is specified\n");
3123 return 1;
3124 } else if (ar == ARG_FOUND) {
3125 gSafeMode = true;
3128 #ifdef XP_WIN
3129 // If the shift key is pressed and the ctrl and / or alt keys are not pressed
3130 // during startup start in safe mode. GetKeyState returns a short and the high
3131 // order bit will be 1 if the key is pressed. By masking the returned short
3132 // with 0x8000 the result will be 0 if the key is not pressed and non-zero
3133 // otherwise.
3134 if (GetKeyState(VK_SHIFT) & 0x8000 &&
3135 !(GetKeyState(VK_CONTROL) & 0x8000) && !(GetKeyState(VK_MENU) & 0x8000)) {
3136 gSafeMode = true;
3138 #endif
3140 #ifdef XP_MACOSX
3141 if (GetCurrentEventKeyModifiers() & optionKey)
3142 gSafeMode = true;
3143 #endif
3145 // Handle -no-remote and -new-instance command line arguments. Setup
3146 // the environment to better accommodate other components and various
3147 // restart scenarios.
3148 ar = CheckArg("no-remote", true);
3149 if (ar == ARG_BAD) {
3150 PR_fprintf(PR_STDERR, "Error: argument -no-remote is invalid when argument -osint is specified\n");
3151 return 1;
3152 } else if (ar == ARG_FOUND) {
3153 SaveToEnv("MOZ_NO_REMOTE=1");
3156 ar = CheckArg("new-instance", true);
3157 if (ar == ARG_BAD) {
3158 PR_fprintf(PR_STDERR, "Error: argument -new-instance is invalid when argument -osint is specified\n");
3159 return 1;
3160 } else if (ar == ARG_FOUND) {
3161 SaveToEnv("MOZ_NEW_INSTANCE=1");
3164 // Handle -help and -version command line arguments.
3165 // They should return quickly, so we deal with them here.
3166 if (CheckArg("h") || CheckArg("help") || CheckArg("?")) {
3167 DumpHelp();
3168 *aExitFlag = true;
3169 return 0;
3172 if (CheckArg("v") || CheckArg("version")) {
3173 DumpVersion();
3174 *aExitFlag = true;
3175 return 0;
3178 #ifdef NS_TRACE_MALLOC
3179 gArgc = NS_TraceMallocStartupArgs(gArgc, gArgv);
3180 #endif
3182 rv = XRE_InitCommandLine(gArgc, gArgv);
3183 NS_ENSURE_SUCCESS(rv, 1);
3185 // Check for -register, which registers chrome and then exits immediately.
3186 ar = CheckArg("register", true);
3187 if (ar == ARG_BAD) {
3188 PR_fprintf(PR_STDERR, "Error: argument -register is invalid when argument -osint is specified\n");
3189 return 1;
3190 } else if (ar == ARG_FOUND) {
3191 ScopedXPCOMStartup xpcom;
3192 rv = xpcom.Initialize();
3193 NS_ENSURE_SUCCESS(rv, 1);
3195 nsCOMPtr<nsIChromeRegistry> chromeReg =
3196 mozilla::services::GetChromeRegistryService();
3197 NS_ENSURE_TRUE(chromeReg, 1);
3199 chromeReg->CheckForNewChrome();
3201 *aExitFlag = true;
3202 return 0;
3205 if (PR_GetEnv("MOZ_RUN_GTEST")) {
3206 int result;
3207 // RunGTest will only be set if we're in xul-unit
3208 if (mozilla::RunGTest) {
3209 result = mozilla::RunGTest();
3210 } else {
3211 result = 1;
3212 printf("TEST-UNEXPECTED-FAIL | gtest | Not compiled with enable-tests\n");
3214 *aExitFlag = true;
3215 return result;
3218 return 0;
3221 #ifdef MOZ_CRASHREPORTER
3222 #ifdef XP_WIN
3224 * Uses WMI to read some manufacturer information that may be useful for
3225 * diagnosing hardware-specific crashes. This function is best-effort; failures
3226 * shouldn't burden the caller. COM must be initialized before calling.
3228 static void AnnotateSystemManufacturer()
3230 nsRefPtr<IWbemLocator> locator;
3232 HRESULT hr = CoCreateInstance(CLSID_WbemLocator, nullptr, CLSCTX_INPROC_SERVER,
3233 IID_IWbemLocator, getter_AddRefs(locator));
3235 if (FAILED(hr)) {
3236 return;
3239 nsRefPtr<IWbemServices> services;
3241 hr = locator->ConnectServer(_bstr_t(L"ROOT\\CIMV2"), nullptr, nullptr, nullptr,
3242 0, nullptr, nullptr, getter_AddRefs(services));
3244 if (FAILED(hr)) {
3245 return;
3248 hr = CoSetProxyBlanket(services, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, nullptr,
3249 RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE,
3250 nullptr, EOAC_NONE);
3252 if (FAILED(hr)) {
3253 return;
3256 nsRefPtr<IEnumWbemClassObject> enumerator;
3258 hr = services->ExecQuery(_bstr_t(L"WQL"), _bstr_t(L"SELECT * FROM Win32_BIOS"),
3259 WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
3260 nullptr, getter_AddRefs(enumerator));
3262 if (FAILED(hr) || !enumerator) {
3263 return;
3266 nsRefPtr<IWbemClassObject> classObject;
3267 ULONG results;
3269 hr = enumerator->Next(WBEM_INFINITE, 1, getter_AddRefs(classObject), &results);
3271 if (FAILED(hr) || results == 0) {
3272 return;
3275 VARIANT value;
3276 VariantInit(&value);
3278 hr = classObject->Get(L"Manufacturer", 0, &value, 0, 0);
3280 if (SUCCEEDED(hr) && V_VT(&value) == VT_BSTR) {
3281 CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("BIOS_Manufacturer"),
3282 NS_ConvertUTF16toUTF8(V_BSTR(&value)));
3285 VariantClear(&value);
3288 static void PR_CALLBACK AnnotateSystemManufacturer_ThreadStart(void*)
3290 HRESULT hr = CoInitialize(nullptr);
3292 if (FAILED(hr)) {
3293 return;
3296 AnnotateSystemManufacturer();
3298 CoUninitialize();
3300 #endif
3301 #endif
3303 namespace mozilla {
3304 ShutdownChecksMode gShutdownChecks = SCM_NOTHING;
3307 static void SetShutdownChecks() {
3308 // Set default first. On debug builds we crash. On nightly and local
3309 // builds we record. Nightlies will then send the info via telemetry,
3310 // but it is usefull to have the data in about:telemetry in local builds
3311 // too.
3313 #ifdef DEBUG
3314 gShutdownChecks = SCM_CRASH;
3315 #else
3316 const char* releaseChannel = NS_STRINGIFY(MOZ_UPDATE_CHANNEL);
3317 if (strcmp(releaseChannel, "nightly") == 0 ||
3318 strcmp(releaseChannel, "default") == 0) {
3319 gShutdownChecks = SCM_RECORD;
3320 } else {
3321 gShutdownChecks = SCM_NOTHING;
3323 #endif
3325 // We let an environment variable override the default so that addons
3326 // authors can use it for debugging shutdown with released firefox versions.
3327 const char* mozShutdownChecksEnv = PR_GetEnv("MOZ_SHUTDOWN_CHECKS");
3328 if (mozShutdownChecksEnv) {
3329 if (strcmp(mozShutdownChecksEnv, "crash") == 0) {
3330 gShutdownChecks = SCM_CRASH;
3331 } else if (strcmp(mozShutdownChecksEnv, "record") == 0) {
3332 gShutdownChecks = SCM_RECORD;
3333 } else if (strcmp(mozShutdownChecksEnv, "nothing") == 0) {
3334 gShutdownChecks = SCM_NOTHING;
3341 * XRE_mainStartup - Initializes the profile and various other services.
3342 * Main() will exit early if either return value != 0 or if aExitFlag is
3343 * true.
3346 XREMain::XRE_mainStartup(bool* aExitFlag)
3348 nsresult rv;
3350 if (!aExitFlag)
3351 return 1;
3352 *aExitFlag = false;
3354 SetShutdownChecks();
3356 #if defined(MOZ_WIDGET_GTK) || defined(MOZ_ENABLE_XREMOTE)
3357 // Stash DESKTOP_STARTUP_ID in malloc'ed memory because gtk_init will clear it.
3358 #define HAVE_DESKTOP_STARTUP_ID
3359 const char* desktopStartupIDEnv = PR_GetEnv("DESKTOP_STARTUP_ID");
3360 if (desktopStartupIDEnv) {
3361 mDesktopStartupID.Assign(desktopStartupIDEnv);
3363 #endif
3365 #if defined(MOZ_WIDGET_QT)
3366 nsQAppInstance::AddRef(gArgc, gArgv, true);
3368 QStringList nonQtArguments = qApp->arguments();
3369 gQtOnlyArgc = 1;
3370 gQtOnlyArgv = (char**) malloc(sizeof(char*)
3371 * (gRestartArgc - nonQtArguments.size() + 2));
3373 // copy binary path
3374 gQtOnlyArgv[0] = gRestartArgv[0];
3376 for (int i = 1; i < gRestartArgc; ++i) {
3377 if (!nonQtArguments.contains(gRestartArgv[i])) {
3378 // copy arguments used by Qt for later
3379 gQtOnlyArgv[gQtOnlyArgc++] = gRestartArgv[i];
3382 gQtOnlyArgv[gQtOnlyArgc] = nullptr;
3383 #endif
3384 #if defined(MOZ_WIDGET_GTK)
3385 // setup for private colormap. Ideally we'd like to do this
3386 // in nsAppShell::Create, but we need to get in before gtk
3387 // has been initialized to make sure everything is running
3388 // consistently.
3389 #if (MOZ_WIDGET_GTK == 2)
3390 if (CheckArg("install"))
3391 gdk_rgb_set_install(TRUE);
3392 #endif
3394 // Set program name to the one defined in application.ini.
3396 nsAutoCString program(gAppData->name);
3397 ToLowerCase(program);
3398 g_set_prgname(program.get());
3401 // Initialize GTK here for splash.
3403 // Open the display ourselves instead of using gtk_init, so that we can
3404 // close it without fear that one day gtk might clean up the display it
3405 // opens.
3406 if (!gtk_parse_args(&gArgc, &gArgv))
3407 return 1;
3409 // display_name is owned by gdk.
3410 const char *display_name = gdk_get_display_arg_name();
3411 if (display_name) {
3412 SaveWordToEnv("DISPLAY", nsDependentCString(display_name));
3413 } else {
3414 display_name = PR_GetEnv("DISPLAY");
3415 if (!display_name) {
3416 PR_fprintf(PR_STDERR, "Error: no display specified\n");
3417 return 1;
3420 #endif /* MOZ_WIDGET_GTK2 */
3422 #ifdef MOZ_ENABLE_XREMOTE
3423 // handle -remote now that xpcom is fired up
3424 bool newInstance;
3426 char *e = PR_GetEnv("MOZ_NO_REMOTE");
3427 mDisableRemote = (e && *e);
3428 if (mDisableRemote) {
3429 newInstance = true;
3430 } else {
3431 e = PR_GetEnv("MOZ_NEW_INSTANCE");
3432 newInstance = (e && *e);
3436 const char* xremotearg;
3437 ArgResult ar = CheckArg("remote", true, &xremotearg);
3438 if (ar == ARG_BAD) {
3439 PR_fprintf(PR_STDERR, "Error: -remote requires an argument\n");
3440 return 1;
3442 const char* desktopStartupIDPtr =
3443 mDesktopStartupID.IsEmpty() ? nullptr : mDesktopStartupID.get();
3444 if (ar) {
3445 *aExitFlag = true;
3446 return HandleRemoteArgument(xremotearg, desktopStartupIDPtr);
3449 if (!newInstance) {
3450 // Try to remote the entire command line. If this fails, start up normally.
3451 RemoteResult rr = RemoteCommandLine(desktopStartupIDPtr);
3452 if (rr == REMOTE_FOUND) {
3453 *aExitFlag = true;
3454 return 0;
3456 else if (rr == REMOTE_ARG_BAD)
3457 return 1;
3459 #endif
3460 #ifdef MOZ_X11
3461 // Init X11 in thread-safe mode. Must be called prior to the first call to XOpenDisplay
3462 // (called inside gdk_display_open). This is a requirement for off main tread compositing.
3463 // This is done only on X11 platforms if the environment variable MOZ_USE_OMTC is set so
3464 // as to avoid overhead when omtc is not used.
3466 // On nightly builds, we call this by default to enable OMTC for Electrolysis testing. On
3467 // aurora, beta, and release builds, there is a small tpaint regression from enabling this
3468 // call, so it sits behind an environment variable.
3470 // An environment variable is used instead of a pref on X11 platforms because we start having
3471 // access to prefs long after the first call to XOpenDisplay which is hard to change due to
3472 // interdependencies in the initialization.
3473 # ifndef NIGHTLY_BUILD
3474 if (PR_GetEnv("MOZ_USE_OMTC") ||
3475 PR_GetEnv("MOZ_OMTC_ENABLED"))
3476 # endif
3478 XInitThreads();
3480 #endif
3481 #if defined(MOZ_WIDGET_GTK)
3482 mGdkDisplay = gdk_display_open(display_name);
3483 if (!mGdkDisplay) {
3484 PR_fprintf(PR_STDERR, "Error: cannot open display: %s\n", display_name);
3485 return 1;
3487 gdk_display_manager_set_default_display (gdk_display_manager_get(),
3488 mGdkDisplay);
3490 // g_set_application_name () is only defined in glib2.2 and higher.
3491 _g_set_application_name_fn _g_set_application_name =
3492 (_g_set_application_name_fn)FindFunction("g_set_application_name");
3493 if (_g_set_application_name) {
3494 _g_set_application_name(mAppData->name);
3496 _gtk_window_set_auto_startup_notification_fn _gtk_window_set_auto_startup_notification =
3497 (_gtk_window_set_auto_startup_notification_fn)FindFunction("gtk_window_set_auto_startup_notification");
3498 if (_gtk_window_set_auto_startup_notification) {
3499 _gtk_window_set_auto_startup_notification(false);
3502 #if (MOZ_WIDGET_GTK == 2)
3503 gtk_widget_set_default_colormap(gdk_rgb_get_colormap());
3504 #endif /* (MOZ_WIDGET_GTK == 2) */
3505 #endif /* defined(MOZ_WIDGET_GTK) */
3506 #ifdef MOZ_X11
3507 // Do this after initializing GDK, or GDK will install its own handler.
3508 InstallX11ErrorHandler();
3509 #endif
3511 // Call the code to install our handler
3512 #ifdef MOZ_JPROF
3513 setupProfilingStuff();
3514 #endif
3516 rv = NS_CreateNativeAppSupport(getter_AddRefs(mNativeApp));
3517 if (NS_FAILED(rv))
3518 return 1;
3520 bool canRun = false;
3521 rv = mNativeApp->Start(&canRun);
3522 if (NS_FAILED(rv) || !canRun) {
3523 return 1;
3526 #if defined(HAVE_DESKTOP_STARTUP_ID) && defined(MOZ_WIDGET_GTK)
3527 // DESKTOP_STARTUP_ID is cleared now,
3528 // we recover it in case we need a restart.
3529 if (!mDesktopStartupID.IsEmpty()) {
3530 nsAutoCString desktopStartupEnv;
3531 desktopStartupEnv.AssignLiteral("DESKTOP_STARTUP_ID=");
3532 desktopStartupEnv.Append(mDesktopStartupID);
3533 // Leak it with extreme prejudice!
3534 PR_SetEnv(ToNewCString(desktopStartupEnv));
3536 #endif
3538 #if defined(USE_MOZ_UPDATER)
3539 // Check for and process any available updates
3540 nsCOMPtr<nsIFile> updRoot;
3541 bool persistent;
3542 rv = mDirProvider.GetFile(XRE_UPDATE_ROOT_DIR, &persistent,
3543 getter_AddRefs(updRoot));
3544 // XRE_UPDATE_ROOT_DIR may fail. Fallback to appDir if failed
3545 if (NS_FAILED(rv))
3546 updRoot = mDirProvider.GetAppDir();
3548 // If the MOZ_PROCESS_UPDATES environment variable already exists, then
3549 // we are being called from the callback application.
3550 if (EnvHasValue("MOZ_PROCESS_UPDATES")) {
3551 // If the caller has asked us to log our arguments, do so. This is used
3552 // to make sure that the maintenance service successfully launches the
3553 // callback application.
3554 const char *logFile = nullptr;
3555 if (ARG_FOUND == CheckArg("dump-args", false, &logFile)) {
3556 FILE* logFP = fopen(logFile, "wb");
3557 if (logFP) {
3558 for (int i = 1; i < gRestartArgc; ++i) {
3559 fprintf(logFP, "%s\n", gRestartArgv[i]);
3561 fclose(logFP);
3564 *aExitFlag = true;
3565 return 0;
3568 // Support for processing an update and exiting. The MOZ_PROCESS_UPDATES
3569 // environment variable will be part of the updater's environment and the
3570 // application that is relaunched by the updater. When the application is
3571 // relaunched by the updater it will be removed below and the application
3572 // will exit.
3573 if (CheckArg("process-updates")) {
3574 SaveToEnv("MOZ_PROCESS_UPDATES=1");
3576 nsCOMPtr<nsIFile> exeFile, exeDir;
3577 rv = mDirProvider.GetFile(XRE_EXECUTABLE_FILE, &persistent,
3578 getter_AddRefs(exeFile));
3579 NS_ENSURE_SUCCESS(rv, 1);
3580 rv = exeFile->GetParent(getter_AddRefs(exeDir));
3581 NS_ENSURE_SUCCESS(rv, 1);
3582 ProcessUpdates(mDirProvider.GetGREDir(),
3583 exeDir,
3584 updRoot,
3585 gRestartArgc,
3586 gRestartArgv,
3587 mAppData->version);
3588 if (EnvHasValue("MOZ_PROCESS_UPDATES")) {
3589 SaveToEnv("MOZ_PROCESS_UPDATES=");
3590 *aExitFlag = true;
3591 return 0;
3593 #endif
3595 rv = NS_NewToolkitProfileService(getter_AddRefs(mProfileSvc));
3596 if (rv == NS_ERROR_FILE_ACCESS_DENIED) {
3597 PR_fprintf(PR_STDERR, "Error: Access was denied while trying to open files in " \
3598 "your profile directory.\n");
3600 if (NS_FAILED(rv)) {
3601 // We failed to choose or create profile - notify user and quit
3602 ProfileMissingDialog(mNativeApp);
3603 return 1;
3606 rv = SelectProfile(getter_AddRefs(mProfileLock), mProfileSvc, mNativeApp, &mStartOffline,
3607 &mProfileName);
3608 if (rv == NS_ERROR_LAUNCHED_CHILD_PROCESS ||
3609 rv == NS_ERROR_ABORT) {
3610 *aExitFlag = true;
3611 return 0;
3614 if (NS_FAILED(rv)) {
3615 // We failed to choose or create profile - notify user and quit
3616 ProfileMissingDialog(mNativeApp);
3617 return 1;
3619 gProfileLock = mProfileLock;
3621 rv = mProfileLock->GetDirectory(getter_AddRefs(mProfD));
3622 NS_ENSURE_SUCCESS(rv, 1);
3624 rv = mProfileLock->GetLocalDirectory(getter_AddRefs(mProfLD));
3625 NS_ENSURE_SUCCESS(rv, 1);
3627 rv = mDirProvider.SetProfile(mProfD, mProfLD);
3628 NS_ENSURE_SUCCESS(rv, 1);
3630 //////////////////////// NOW WE HAVE A PROFILE ////////////////////////
3632 #ifdef MOZ_CRASHREPORTER
3633 if (mAppData->flags & NS_XRE_ENABLE_CRASH_REPORTER)
3634 MakeOrSetMinidumpPath(mProfD);
3635 #endif
3637 nsAutoCString version;
3638 BuildVersion(version);
3640 #ifdef TARGET_OS_ABI
3641 NS_NAMED_LITERAL_CSTRING(osABI, TARGET_OS_ABI);
3642 #else
3643 // No TARGET_XPCOM_ABI, but at least the OS is known
3644 NS_NAMED_LITERAL_CSTRING(osABI, OS_TARGET "_UNKNOWN");
3645 #endif
3647 // Check for version compatibility with the last version of the app this
3648 // profile was started with. The format of the version stamp is defined
3649 // by the BuildVersion function.
3650 // Also check to see if something has happened to invalidate our
3651 // fastload caches, like an extension upgrade or installation.
3653 // If we see .purgecaches, that means someone did a make.
3654 // Re-register components to catch potential changes.
3655 nsCOMPtr<nsIFile> flagFile;
3657 rv = NS_ERROR_FILE_NOT_FOUND;
3658 nsCOMPtr<nsIFile> fFlagFile;
3659 if (mAppData->directory) {
3660 rv = mAppData->directory->Clone(getter_AddRefs(fFlagFile));
3662 flagFile = do_QueryInterface(fFlagFile);
3663 if (flagFile) {
3664 flagFile->AppendNative(FILE_INVALIDATE_CACHES);
3667 bool cachesOK;
3668 bool versionOK = CheckCompatibility(mProfD, version, osABI,
3669 mDirProvider.GetGREDir(),
3670 mAppData->directory, flagFile,
3671 &cachesOK);
3672 if (CheckArg("purgecaches")) {
3673 cachesOK = false;
3675 if (PR_GetEnv("MOZ_PURGE_CACHES")) {
3676 cachesOK = false;
3679 // Every time a profile is loaded by a build with a different version,
3680 // it updates the compatibility.ini file saying what version last wrote
3681 // the fastload caches. On subsequent launches if the version matches,
3682 // there is no need for re-registration. If the user loads the same
3683 // profile in different builds the component registry must be
3684 // re-generated to prevent mysterious component loading failures.
3686 bool startupCacheValid = true;
3687 if (gSafeMode) {
3688 startupCacheValid = RemoveComponentRegistries(mProfD, mProfLD, false);
3689 WriteVersion(mProfD, NS_LITERAL_CSTRING("Safe Mode"), osABI,
3690 mDirProvider.GetGREDir(), mAppData->directory, !startupCacheValid);
3692 else if (versionOK) {
3693 if (!cachesOK) {
3694 // Remove caches, forcing component re-registration.
3695 // The new list of additional components directories is derived from
3696 // information in "extensions.ini".
3697 startupCacheValid = RemoveComponentRegistries(mProfD, mProfLD, false);
3699 // Rewrite compatibility.ini to remove the flag
3700 WriteVersion(mProfD, version, osABI,
3701 mDirProvider.GetGREDir(), mAppData->directory, !startupCacheValid);
3703 // Nothing need be done for the normal startup case.
3705 else {
3706 // Remove caches, forcing component re-registration
3707 // with the default set of components (this disables any potentially
3708 // troublesome incompatible XPCOM components).
3709 startupCacheValid = RemoveComponentRegistries(mProfD, mProfLD, true);
3711 // Write out version
3712 WriteVersion(mProfD, version, osABI,
3713 mDirProvider.GetGREDir(), mAppData->directory, !startupCacheValid);
3716 if (!startupCacheValid)
3717 StartupCache::IgnoreDiskCache();
3719 if (flagFile) {
3720 flagFile->Remove(true);
3723 return 0;
3727 * XRE_mainRun - Command line startup, profile migration, and
3728 * the calling of appStartup->Run().
3730 nsresult
3731 XREMain::XRE_mainRun()
3733 nsresult rv = NS_OK;
3734 NS_ASSERTION(mScopedXPCom, "Scoped xpcom not initialized.");
3736 #ifdef NS_FUNCTION_TIMER
3737 // initialize some common services, so we don't pay the cost for these at odd times later on;
3738 // SetWindowCreator -> ChromeRegistry -> IOService -> SocketTransportService -> (nspr wspm init), Prefs
3740 nsCOMPtr<nsISupports> comp;
3742 comp = do_GetService("@mozilla.org/preferences-service;1");
3744 comp = do_GetService("@mozilla.org/network/socket-transport-service;1");
3746 comp = do_GetService("@mozilla.org/network/dns-service;1");
3748 comp = do_GetService("@mozilla.org/network/io-service;1");
3750 comp = do_GetService("@mozilla.org/chrome/chrome-registry;1");
3752 comp = do_GetService("@mozilla.org/focus-event-suppressor-service;1");
3754 #endif
3756 rv = mScopedXPCom->SetWindowCreator(mNativeApp);
3757 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
3759 #ifdef MOZ_CRASHREPORTER
3760 // tell the crash reporter to also send the release channel
3761 nsCOMPtr<nsIPrefService> prefs = do_GetService("@mozilla.org/preferences-service;1", &rv);
3762 if (NS_SUCCEEDED(rv)) {
3763 nsCOMPtr<nsIPrefBranch> defaultPrefBranch;
3764 rv = prefs->GetDefaultBranch(nullptr, getter_AddRefs(defaultPrefBranch));
3766 if (NS_SUCCEEDED(rv)) {
3767 nsXPIDLCString sval;
3768 rv = defaultPrefBranch->GetCharPref("app.update.channel", getter_Copies(sval));
3769 if (NS_SUCCEEDED(rv)) {
3770 CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("ReleaseChannel"),
3771 sval);
3775 // Needs to be set after xpcom initialization.
3776 CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("FramePoisonBase"),
3777 nsPrintfCString("%.16llx", uint64_t(gMozillaPoisonBase)));
3778 CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("FramePoisonSize"),
3779 nsPrintfCString("%lu", uint32_t(gMozillaPoisonSize)));
3781 #ifdef XP_WIN
3782 PR_CreateThread(PR_USER_THREAD, AnnotateSystemManufacturer_ThreadStart, 0,
3783 PR_PRIORITY_LOW, PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD, 0);
3784 #endif
3786 #endif
3788 if (mStartOffline) {
3789 nsCOMPtr<nsIIOService2> io (do_GetService("@mozilla.org/network/io-service;1"));
3790 NS_ENSURE_TRUE(io, NS_ERROR_FAILURE);
3791 io->SetManageOfflineStatus(false);
3792 io->SetOffline(true);
3796 nsCOMPtr<nsIObserver> startupNotifier
3797 (do_CreateInstance(NS_APPSTARTUPNOTIFIER_CONTRACTID, &rv));
3798 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
3800 startupNotifier->Observe(nullptr, APPSTARTUP_TOPIC, nullptr);
3803 nsCOMPtr<nsIAppStartup> appStartup
3804 (do_GetService(NS_APPSTARTUP_CONTRACTID));
3805 NS_ENSURE_TRUE(appStartup, NS_ERROR_FAILURE);
3807 if (gDoMigration) {
3808 nsCOMPtr<nsIFile> file;
3809 mDirProvider.GetAppDir()->Clone(getter_AddRefs(file));
3810 file->AppendNative(NS_LITERAL_CSTRING("override.ini"));
3811 nsINIParser parser;
3812 nsresult rv = parser.Init(file);
3813 if (NS_SUCCEEDED(rv)) {
3814 nsAutoCString buf;
3815 rv = parser.GetString("XRE", "EnableProfileMigrator", buf);
3816 if (NS_SUCCEEDED(rv)) {
3817 if (buf[0] == '0' || buf[0] == 'f' || buf[0] == 'F') {
3818 gDoMigration = false;
3825 nsCOMPtr<nsIToolkitProfile> selectedProfile;
3826 if (gDoProfileReset) {
3827 // At this point we can be sure that profile reset is happening on the default profile.
3828 rv = mProfileSvc->GetSelectedProfile(getter_AddRefs(selectedProfile));
3829 if (NS_FAILED(rv)) {
3830 gDoProfileReset = false;
3831 return NS_ERROR_FAILURE;
3835 // Profile Migration
3836 if (mAppData->flags & NS_XRE_ENABLE_PROFILE_MIGRATOR && gDoMigration) {
3837 gDoMigration = false;
3838 nsCOMPtr<nsIProfileMigrator> pm(do_CreateInstance(NS_PROFILEMIGRATOR_CONTRACTID));
3839 if (pm) {
3840 nsAutoCString aKey;
3841 if (gDoProfileReset) {
3842 // Automatically migrate from the current application if we just
3843 // reset the profile.
3844 aKey = MOZ_APP_NAME;
3846 pm->Migrate(&mDirProvider, aKey);
3850 if (gDoProfileReset) {
3851 nsresult backupCreated = ProfileResetCleanup(selectedProfile);
3852 if (NS_FAILED(backupCreated)) NS_WARNING("Could not cleanup the profile that was reset");
3854 // Set the new profile as the default after we're done cleaning up the old default.
3855 rv = SetCurrentProfileAsDefault(mProfileSvc, mProfD);
3856 if (NS_FAILED(rv)) NS_WARNING("Could not set current profile as the default");
3860 mDirProvider.DoStartup();
3862 #ifdef MOZ_CRASHREPORTER
3863 nsCString userAgentLocale;
3864 if (NS_SUCCEEDED(Preferences::GetCString("general.useragent.locale", &userAgentLocale))) {
3865 CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("useragent_locale"), userAgentLocale);
3867 #endif
3869 appStartup->GetShuttingDown(&mShuttingDown);
3871 nsCOMPtr<nsICommandLineRunner> cmdLine;
3873 nsCOMPtr<nsIFile> workingDir;
3874 rv = NS_GetSpecialDirectory(NS_OS_CURRENT_WORKING_DIR, getter_AddRefs(workingDir));
3875 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
3877 if (!mShuttingDown) {
3878 cmdLine = do_CreateInstance("@mozilla.org/toolkit/command-line;1");
3879 NS_ENSURE_TRUE(cmdLine, NS_ERROR_FAILURE);
3881 rv = cmdLine->Init(gArgc, gArgv, workingDir,
3882 nsICommandLine::STATE_INITIAL_LAUNCH);
3883 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
3885 /* Special-case services that need early access to the command
3886 line. */
3887 nsCOMPtr<nsIObserverService> obsService =
3888 mozilla::services::GetObserverService();
3889 if (obsService) {
3890 obsService->NotifyObservers(cmdLine, "command-line-startup", nullptr);
3894 SaveStateForAppInitiatedRestart();
3896 // clear out any environment variables which may have been set
3897 // during the relaunch process now that we know we won't be relaunching.
3898 SaveToEnv("XRE_PROFILE_PATH=");
3899 SaveToEnv("XRE_PROFILE_LOCAL_PATH=");
3900 SaveToEnv("XRE_PROFILE_NAME=");
3901 SaveToEnv("XRE_START_OFFLINE=");
3902 SaveToEnv("NO_EM_RESTART=");
3903 SaveToEnv("XUL_APP_FILE=");
3904 SaveToEnv("XRE_BINARY_PATH=");
3906 if (!mShuttingDown) {
3907 rv = appStartup->CreateHiddenWindow();
3908 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
3910 #if defined(HAVE_DESKTOP_STARTUP_ID) && defined(MOZ_WIDGET_GTK)
3911 nsGTKToolkit* toolkit = nsGTKToolkit::GetToolkit();
3912 if (toolkit && !mDesktopStartupID.IsEmpty()) {
3913 toolkit->SetDesktopStartupID(mDesktopStartupID);
3915 // Clear the environment variable so it won't be inherited by
3916 // child processes and confuse things.
3917 g_unsetenv ("DESKTOP_STARTUP_ID");
3918 #endif
3920 #ifdef XP_MACOSX
3921 // Set up ability to respond to system (Apple) events. This must be
3922 // done before setting up the command line service.
3923 SetupMacApplicationDelegate();
3925 // we re-initialize the command-line service and do appleevents munging
3926 // after we are sure that we're not restarting
3927 cmdLine = do_CreateInstance("@mozilla.org/toolkit/command-line;1");
3928 NS_ENSURE_TRUE(cmdLine, NS_ERROR_FAILURE);
3930 CommandLineServiceMac::SetupMacCommandLine(gArgc, gArgv, false);
3932 rv = cmdLine->Init(gArgc, gArgv,
3933 workingDir, nsICommandLine::STATE_INITIAL_LAUNCH);
3934 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
3935 #endif
3937 nsCOMPtr<nsIObserverService> obsService =
3938 mozilla::services::GetObserverService();
3939 if (obsService)
3940 obsService->NotifyObservers(nullptr, "final-ui-startup", nullptr);
3942 (void)appStartup->DoneStartingUp();
3943 appStartup->GetShuttingDown(&mShuttingDown);
3946 if (!mShuttingDown) {
3947 rv = cmdLine->Run();
3948 NS_ENSURE_SUCCESS_LOG(rv, NS_ERROR_FAILURE);
3950 appStartup->GetShuttingDown(&mShuttingDown);
3953 if (!mShuttingDown) {
3954 #ifdef MOZ_ENABLE_XREMOTE
3955 // if we have X remote support, start listening for requests on the
3956 // proxy window.
3957 if (!mDisableRemote)
3958 mRemoteService = do_GetService("@mozilla.org/toolkit/remote-service;1");
3959 if (mRemoteService)
3960 mRemoteService->Startup(mAppData->name, mProfileName.get());
3961 #endif /* MOZ_ENABLE_XREMOTE */
3963 mNativeApp->Enable();
3966 #ifdef MOZ_INSTRUMENT_EVENT_LOOP
3967 if (PR_GetEnv("MOZ_INSTRUMENT_EVENT_LOOP") || profiler_is_active()) {
3968 bool logToConsole = !!PR_GetEnv("MOZ_INSTRUMENT_EVENT_LOOP");
3969 mozilla::InitEventTracing(logToConsole);
3971 #endif /* MOZ_INSTRUMENT_EVENT_LOOP */
3974 rv = appStartup->Run();
3975 if (NS_FAILED(rv)) {
3976 NS_ERROR("failed to run appstartup");
3977 gLogConsoleErrors = true;
3981 return rv;
3985 * XRE_main - A class based main entry point used by most platforms.
3988 XREMain::XRE_main(int argc, char* argv[], const nsXREAppData* aAppData)
3990 char aLocal;
3991 GeckoProfilerInitRAII profilerGuard(&aLocal);
3992 PROFILER_LABEL("Startup", "XRE_Main");
3994 nsresult rv = NS_OK;
3996 gArgc = argc;
3997 gArgv = argv;
3999 NS_ENSURE_TRUE(aAppData, 2);
4001 mAppData = new ScopedAppData(aAppData);
4002 if (!mAppData)
4003 return 1;
4004 // used throughout this file
4005 gAppData = mAppData;
4007 ScopedLogging log;
4009 #if defined(MOZ_WIDGET_GTK)
4010 #if defined(MOZ_MEMORY) || defined(__FreeBSD__) \
4011 || defined(__NetBSD__) && __NetBSD_Version__ >= 500000000
4012 // Disable the slice allocator, since jemalloc already uses similar layout
4013 // algorithms, and using a sub-allocator tends to increase fragmentation.
4014 // This must be done before g_thread_init() is called.
4015 g_slice_set_config(G_SLICE_CONFIG_ALWAYS_MALLOC, 1);
4016 #endif
4017 g_thread_init(nullptr);
4018 #endif
4020 // init
4021 bool exit = false;
4022 int result = XRE_mainInit(&exit);
4023 if (result != 0 || exit)
4024 return result;
4026 // startup
4027 result = XRE_mainStartup(&exit);
4028 if (result != 0 || exit)
4029 return result;
4031 bool appInitiatedRestart = false;
4033 // Start the real application
4034 mScopedXPCom = new ScopedXPCOMStartup();
4035 if (!mScopedXPCom)
4036 return 1;
4038 rv = mScopedXPCom->Initialize();
4039 NS_ENSURE_SUCCESS(rv, 1);
4041 // run!
4042 rv = XRE_mainRun();
4044 #ifdef MOZ_INSTRUMENT_EVENT_LOOP
4045 mozilla::ShutdownEventTracing();
4046 #endif
4048 // Check for an application initiated restart. This is one that
4049 // corresponds to nsIAppStartup.quit(eRestart)
4050 if (rv == NS_SUCCESS_RESTART_APP) {
4051 appInitiatedRestart = true;
4053 // We have an application restart don't do any shutdown checks here
4054 // In particular we don't want to poison IO for checking late-writes.
4055 gShutdownChecks = SCM_NOTHING;
4058 if (!mShuttingDown) {
4059 #ifdef MOZ_ENABLE_XREMOTE
4060 // shut down the x remote proxy window
4061 if (mRemoteService) {
4062 mRemoteService->Shutdown();
4064 #endif /* MOZ_ENABLE_XREMOTE */
4067 delete mScopedXPCom;
4068 mScopedXPCom = nullptr;
4070 // unlock the profile after ScopedXPCOMStartup object (xpcom)
4071 // has gone out of scope. see bug #386739 for more details
4072 mProfileLock->Unlock();
4073 gProfileLock = nullptr;
4075 #if defined(MOZ_WIDGET_QT)
4076 nsQAppInstance::Release();
4077 #endif
4079 // Restart the app after XPCOM has been shut down cleanly.
4080 if (appInitiatedRestart) {
4081 RestoreStateForAppInitiatedRestart();
4083 // Ensure that these environment variables are set:
4084 SaveFileToEnvIfUnset("XRE_PROFILE_PATH", mProfD);
4085 SaveFileToEnvIfUnset("XRE_PROFILE_LOCAL_PATH", mProfLD);
4086 SaveWordToEnvIfUnset("XRE_PROFILE_NAME", mProfileName);
4088 #ifdef MOZ_WIDGET_GTK
4089 MOZ_gdk_display_close(mGdkDisplay);
4090 #endif
4092 rv = LaunchChild(mNativeApp, true);
4094 #ifdef MOZ_CRASHREPORTER
4095 if (mAppData->flags & NS_XRE_ENABLE_CRASH_REPORTER)
4096 CrashReporter::UnsetExceptionHandler();
4097 #endif
4098 return rv == NS_ERROR_LAUNCHED_CHILD_PROCESS ? 0 : 1;
4101 #ifdef MOZ_WIDGET_GTK
4102 // gdk_display_close also calls gdk_display_manager_set_default_display
4103 // appropriately when necessary.
4104 MOZ_gdk_display_close(mGdkDisplay);
4105 #endif
4107 #ifdef MOZ_CRASHREPORTER
4108 if (mAppData->flags & NS_XRE_ENABLE_CRASH_REPORTER)
4109 CrashReporter::UnsetExceptionHandler();
4110 #endif
4112 XRE_DeinitCommandLine();
4114 return NS_FAILED(rv) ? 1 : 0;
4117 #if defined(MOZ_METRO) && defined(XP_WIN)
4118 extern bool XRE_MetroCoreApplicationRun();
4119 static XREMain* xreMainPtr;
4121 // must be called by the thread we want as the main thread
4122 nsresult
4123 XRE_metroStartup(bool runXREMain)
4125 nsresult rv;
4127 bool exit = false;
4128 if (xreMainPtr->XRE_mainStartup(&exit) != 0 || exit)
4129 return NS_ERROR_FAILURE;
4131 // Start the real application
4132 xreMainPtr->mScopedXPCom = new ScopedXPCOMStartup();
4133 if (!xreMainPtr->mScopedXPCom)
4134 return NS_ERROR_FAILURE;
4136 rv = xreMainPtr->mScopedXPCom->Initialize();
4137 NS_ENSURE_SUCCESS(rv, rv);
4139 if (runXREMain) {
4140 rv = xreMainPtr->XRE_mainRun();
4141 NS_ENSURE_SUCCESS(rv, rv);
4143 return NS_OK;
4146 void
4147 XRE_metroShutdown()
4149 delete xreMainPtr->mScopedXPCom;
4150 xreMainPtr->mScopedXPCom = nullptr;
4152 #ifdef MOZ_INSTRUMENT_EVENT_LOOP
4153 mozilla::ShutdownEventTracing();
4154 #endif
4156 // unlock the profile after ScopedXPCOMStartup object (xpcom)
4157 // has gone out of scope. see bug #386739 for more details
4158 xreMainPtr->mProfileLock->Unlock();
4159 gProfileLock = nullptr;
4161 #ifdef MOZ_CRASHREPORTER
4162 if (xreMainPtr->mAppData->flags & NS_XRE_ENABLE_CRASH_REPORTER)
4163 CrashReporter::UnsetExceptionHandler();
4164 #endif
4166 XRE_DeinitCommandLine();
4169 class WinRTInitWrapper
4171 public:
4172 WinRTInitWrapper() {
4173 mResult = ::RoInitialize(RO_INIT_MULTITHREADED);
4175 ~WinRTInitWrapper() {
4176 if (SUCCEEDED(mResult)) {
4177 ::RoUninitialize();
4180 HRESULT mResult;
4184 XRE_mainMetro(int argc, char* argv[], const nsXREAppData* aAppData)
4186 char aLocal;
4187 GeckoProfilerInitRAII profilerGuard(&aLocal);
4188 PROFILER_LABEL("Startup", "XRE_Main");
4190 nsresult rv = NS_OK;
4192 xreMainPtr = new XREMain();
4193 if (!xreMainPtr) {
4194 return 1;
4197 // Inits Winrt and COM underneath it.
4198 WinRTInitWrapper wrap;
4200 gArgc = argc;
4201 gArgv = argv;
4203 NS_ENSURE_TRUE(aAppData, 2);
4205 xreMainPtr->mAppData = new ScopedAppData(aAppData);
4206 if (!xreMainPtr->mAppData)
4207 return 1;
4208 // used throughout this file
4209 gAppData = xreMainPtr->mAppData;
4211 ScopedLogging log;
4213 // init
4214 bool exit = false;
4215 if (xreMainPtr->XRE_mainInit(&exit) != 0 || exit)
4216 return 1;
4218 // Located in widget, will call back into XRE_metroStartup and
4219 // XRE_metroShutdown above.
4220 if (!XRE_MetroCoreApplicationRun()) {
4221 return 1;
4224 // XRE_metroShutdown should have already been called on the worker
4225 // thread that called XRE_metroStartup.
4226 NS_ASSERTION(!xreMainPtr->mScopedXPCom,
4227 "XPCOM Shutdown hasn't occured, and we are exiting.");
4228 return 0;
4231 void SetWindowsEnvironment(WindowsEnvironmentType aEnvID);
4232 #endif // MOZ_METRO || !defined(XP_WIN)
4234 void
4235 XRE_StopLateWriteChecks(void) {
4236 mozilla::StopLateWriteChecks();
4240 XRE_main(int argc, char* argv[], const nsXREAppData* aAppData, uint32_t aFlags)
4242 #if !defined(MOZ_METRO) || !defined(XP_WIN)
4243 XREMain main;
4244 int result = main.XRE_main(argc, argv, aAppData);
4245 mozilla::RecordShutdownEndTimeStamp();
4246 return result;
4247 #else
4248 if (aFlags == XRE_MAIN_FLAG_USE_METRO) {
4249 SetWindowsEnvironment(WindowsEnvironmentType_Metro);
4252 // Desktop
4253 if (XRE_GetWindowsEnvironment() == WindowsEnvironmentType_Desktop) {
4254 XREMain main;
4255 int result = main.XRE_main(argc, argv, aAppData);
4256 mozilla::RecordShutdownEndTimeStamp();
4257 return result;
4260 // Metro
4261 NS_ASSERTION(XRE_GetWindowsEnvironment() == WindowsEnvironmentType_Metro,
4262 "Unknown Windows environment");
4264 int result = XRE_mainMetro(argc, argv, aAppData);
4265 mozilla::RecordShutdownEndTimeStamp();
4266 return result;
4267 #endif // MOZ_METRO || !defined(XP_WIN)
4270 nsresult
4271 XRE_InitCommandLine(int aArgc, char* aArgv[])
4273 nsresult rv = NS_OK;
4275 #if defined(OS_WIN)
4276 CommandLine::Init(aArgc, aArgv);
4277 #else
4279 // these leak on error, but that's OK: we'll just exit()
4280 char** canonArgs = new char*[aArgc];
4282 // get the canonical version of the binary's path
4283 nsCOMPtr<nsIFile> binFile;
4284 rv = XRE_GetBinaryPath(aArgv[0], getter_AddRefs(binFile));
4285 if (NS_FAILED(rv))
4286 return NS_ERROR_FAILURE;
4288 nsAutoCString canonBinPath;
4289 rv = binFile->GetNativePath(canonBinPath);
4290 if (NS_FAILED(rv))
4291 return NS_ERROR_FAILURE;
4293 canonArgs[0] = strdup(canonBinPath.get());
4295 for (int i = 1; i < aArgc; ++i) {
4296 if (aArgv[i]) {
4297 canonArgs[i] = strdup(aArgv[i]);
4301 NS_ASSERTION(!CommandLine::IsInitialized(), "Bad news!");
4302 CommandLine::Init(aArgc, canonArgs);
4304 for (int i = 0; i < aArgc; ++i)
4305 free(canonArgs[i]);
4306 delete[] canonArgs;
4307 #endif
4309 const char *path = nullptr;
4310 ArgResult ar = CheckArg("greomni", false, &path);
4311 if (ar == ARG_BAD) {
4312 PR_fprintf(PR_STDERR, "Error: argument -greomni requires a path argument\n");
4313 return NS_ERROR_FAILURE;
4316 if (!path)
4317 return rv;
4319 nsCOMPtr<nsIFile> greOmni;
4320 rv = XRE_GetFileFromPath(path, getter_AddRefs(greOmni));
4321 if (NS_FAILED(rv)) {
4322 PR_fprintf(PR_STDERR, "Error: argument -greomni requires a valid path\n");
4323 return rv;
4326 ar = CheckArg("appomni", false, &path);
4327 if (ar == ARG_BAD) {
4328 PR_fprintf(PR_STDERR, "Error: argument -appomni requires a path argument\n");
4329 return NS_ERROR_FAILURE;
4332 nsCOMPtr<nsIFile> appOmni;
4333 if (path) {
4334 rv = XRE_GetFileFromPath(path, getter_AddRefs(appOmni));
4335 if (NS_FAILED(rv)) {
4336 PR_fprintf(PR_STDERR, "Error: argument -appomni requires a valid path\n");
4337 return rv;
4341 mozilla::Omnijar::Init(greOmni, appOmni);
4342 return rv;
4345 nsresult
4346 XRE_DeinitCommandLine()
4348 nsresult rv = NS_OK;
4350 CommandLine::Terminate();
4352 return rv;
4355 GeckoProcessType
4356 XRE_GetProcessType()
4358 return mozilla::startup::sChildProcessType;
4361 void
4362 SetupErrorHandling(const char* progname)
4364 #ifdef XP_WIN
4365 /* On Windows XPSP3 and Windows Vista if DEP is configured off-by-default
4366 we still want DEP protection: enable it explicitly and programmatically.
4368 This function is not available on WinXPSP2 so we dynamically load it.
4371 HMODULE kernel32 = GetModuleHandleW(L"kernel32.dll");
4372 SetProcessDEPPolicyFunc _SetProcessDEPPolicy =
4373 (SetProcessDEPPolicyFunc) GetProcAddress(kernel32, "SetProcessDEPPolicy");
4374 if (_SetProcessDEPPolicy)
4375 _SetProcessDEPPolicy(PROCESS_DEP_ENABLE);
4376 #endif
4378 #ifdef XP_WIN32
4379 // Suppress the "DLL Foo could not be found" dialog, such that if dependent
4380 // libraries (such as GDI+) are not preset, we gracefully fail to load those
4381 // XPCOM components, instead of being ungraceful.
4382 UINT realMode = SetErrorMode(0);
4383 realMode |= SEM_FAILCRITICALERRORS;
4384 // If XRE_NO_WINDOWS_CRASH_DIALOG is set, suppress displaying the "This
4385 // application has crashed" dialog box. This is mainly useful for
4386 // automated testing environments, e.g. tinderbox, where there's no need
4387 // for a dozen of the dialog boxes to litter the console
4388 if (getenv("XRE_NO_WINDOWS_CRASH_DIALOG"))
4389 realMode |= SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX;
4391 SetErrorMode(realMode);
4393 #endif
4395 #if defined (DEBUG) && defined(XP_WIN)
4396 // Send MSCRT Warnings, Errors and Assertions to stderr.
4397 // See http://msdn.microsoft.com/en-us/library/1y71x448(v=VS.80).aspx
4398 // and http://msdn.microsoft.com/en-us/library/a68f826y(v=VS.80).aspx.
4400 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
4401 _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
4402 _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
4403 _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
4404 _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
4405 _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
4407 _CrtSetReportHook(MSCRTReportHook);
4408 #endif
4410 #ifndef XP_OS2
4411 InstallSignalHandlers(progname);
4412 #endif
4414 // Unbuffer stdout, needed for tinderbox tests.
4415 setbuf(stdout, 0);