Bug 575855 - Fix for transitions from fullscreen briefly show an aero basic window...
[mozilla-central.git] / toolkit / xre / nsAppRunner.cpp
blob963706e6d80d5d2985f0ffff8eb524dacce47aae
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Original Code is Mozilla Communicator client code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
23 * Roland Mainz <roland.mainz@informatik.med.uni-giessen.de>
24 * Benjamin Smedberg <benjamin@smedbergs.us>
25 * Ben Goodger <ben@mozilla.org>
26 * Fredrik Holmqvist <thesuckiestemail@yahoo.se>
27 * Ben Turner <mozilla@songbirdnest.com>
28 * Sergei Dolgov <sergei_d@fi.tartu.ee>
30 * Alternatively, the contents of this file may be used under the terms of
31 * either the GNU General Public License Version 2 or later (the "GPL"), or
32 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
33 * in which case the provisions of the GPL or the LGPL are applicable instead
34 * of those above. If you wish to allow use of your version of this file only
35 * under the terms of either the GPL or the LGPL, and not to allow others to
36 * use your version of this file under the terms of the MPL, indicate your
37 * decision by deleting the provisions above and replace them with the notice
38 * and other provisions required by the GPL or the LGPL. If you do not delete
39 * the provisions above, a recipient may use your version of this file under
40 * the terms of any one of the MPL, the GPL or the LGPL.
42 * ***** END LICENSE BLOCK ***** */
44 #if defined(XP_OS2) && defined(MOZ_OS2_HIGH_MEMORY)
45 // os2safe.h has to be included before os2.h, needed for high mem
46 #include <os2safe.h>
47 #endif
49 #define XPCOM_TRANSLATE_NSGM_ENTRY_POINT 1
51 #if defined(MOZ_WIDGET_QT)
52 #include <QtGui/QApplication>
53 #include <QtCore/QScopedPointer>
54 #include <QtGui/QApplication>
55 #include <QtGui/QInputContextFactory>
56 #include <QtGui/QInputContext>
57 #ifdef MOZ_ENABLE_MEEGOTOUCH
58 #include <MApplication>
59 #include "MozMeegoAppService.h"
60 #endif // MOZ_ENABLE_MEEGOTOUCH
61 #endif // MOZ_WIDGET_QT
63 #ifdef MOZ_IPC
64 #include "mozilla/dom/ContentParent.h"
65 using mozilla::dom::ContentParent;
66 #endif
68 #include "nsAppRunner.h"
69 #include "nsUpdateDriver.h"
71 #ifdef XP_MACOSX
72 #include "MacLaunchHelper.h"
73 #include "MacApplicationDelegate.h"
74 #include "MacAutoreleasePool.h"
75 #endif
77 #ifdef XP_OS2
78 #include "private/pprthred.h"
79 #endif
80 #include "prmem.h"
81 #include "prnetdb.h"
82 #include "prprf.h"
83 #include "prproces.h"
84 #include "prenv.h"
86 #include "nsIAppShellService.h"
87 #include "nsIAppStartup.h"
88 #include "nsIAppStartupNotifier.h"
89 #include "nsIMutableArray.h"
90 #include "nsICategoryManager.h"
91 #include "nsIChromeRegistry.h"
92 #include "nsICommandLineRunner.h"
93 #include "nsIComponentManager.h"
94 #include "nsIComponentRegistrar.h"
95 #include "nsIContentHandler.h"
96 #include "nsIDialogParamBlock.h"
97 #include "nsIDOMWindow.h"
98 #include "nsIFastLoadService.h" // for PLATFORM_FASL_SUFFIX
99 #include "mozilla/ModuleUtils.h"
100 #include "nsIIOService2.h"
101 #include "nsIObserverService.h"
102 #include "nsINativeAppSupport.h"
103 #include "nsIProcess.h"
104 #include "nsIProfileUnlocker.h"
105 #include "nsIPromptService.h"
106 #include "nsIServiceManager.h"
107 #include "nsIStringBundle.h"
108 #include "nsISupportsPrimitives.h"
109 #include "nsITimelineService.h"
110 #include "nsIToolkitChromeRegistry.h"
111 #include "nsIToolkitProfile.h"
112 #include "nsIToolkitProfileService.h"
113 #include "nsIURI.h"
114 #include "nsIWindowCreator.h"
115 #include "nsIWindowMediator.h"
116 #include "nsIWindowWatcher.h"
117 #include "nsIXULAppInfo.h"
118 #include "nsIXULRuntime.h"
119 #include "nsPIDOMWindow.h"
120 #include "nsIBaseWindow.h"
121 #include "nsIWidget.h"
122 #include "nsIDocShell.h"
123 #include "nsAppShellCID.h"
125 #include "mozilla/FunctionTimer.h"
127 #ifdef XP_WIN
128 #include "nsIWinAppHelper.h"
129 #include <windows.h>
131 #ifndef PROCESS_DEP_ENABLE
132 #define PROCESS_DEP_ENABLE 0x1
133 #endif
134 #endif
136 #include "nsCRT.h"
137 #include "nsCOMPtr.h"
138 #include "nsDirectoryServiceDefs.h"
139 #include "nsDirectoryServiceUtils.h"
140 #include "nsEmbedCID.h"
141 #include "nsNetUtil.h"
142 #include "nsReadableUtils.h"
143 #include "nsStaticComponents.h"
144 #include "nsXPCOM.h"
145 #include "nsXPCOMCIDInternal.h"
146 #include "nsXPIDLString.h"
147 #include "nsVersionComparator.h"
149 #include "nsAppDirectoryServiceDefs.h"
150 #include "nsXULAppAPI.h"
151 #include "nsXREDirProvider.h"
152 #include "nsToolkitCompsCID.h"
154 #include "nsINIParser.h"
155 #include "mozilla/Omnijar.h"
157 #include <stdlib.h>
159 #if defined(MOZ_SPLASHSCREEN)
160 #include "nsSplashScreen.h"
161 #endif
163 #ifdef XP_UNIX
164 #include <sys/stat.h>
165 #include <unistd.h>
166 #include <pwd.h>
167 #endif
169 #ifdef XP_BEOS
170 // execv() behaves bit differently in R5 and Zeta, looks unreliable in such situation
171 //#include <unistd.h>
172 #include <AppKit.h>
173 #include <AppFileInfo.h>
174 #endif //XP_BEOS
176 #ifdef XP_WIN
177 #ifndef WINCE
178 #include <process.h>
179 #include <shlobj.h>
180 #endif
181 #include "nsThreadUtils.h"
182 #endif
184 #ifdef XP_MACOSX
185 #include "nsILocalFileMac.h"
186 #include "nsCommandLineServiceMac.h"
187 #endif
189 // for X remote support
190 #ifdef MOZ_ENABLE_XREMOTE
191 #include "XRemoteClient.h"
192 #include "nsIRemoteService.h"
193 #endif
195 #ifdef NS_TRACE_MALLOC
196 #include "nsTraceMalloc.h"
197 #endif
199 #if defined(DEBUG) && defined(XP_WIN32)
200 #include <malloc.h>
201 #endif
203 #if defined (XP_MACOSX)
204 #include <Carbon/Carbon.h>
205 #endif
207 #ifdef DEBUG
208 #include "prlog.h"
209 #endif
211 #ifdef MOZ_JPROF
212 #include "jprof.h"
213 #endif
215 #ifdef MOZ_CRASHREPORTER
216 #include "nsExceptionHandler.h"
217 #include "nsICrashReporter.h"
218 #define NS_CRASHREPORTER_CONTRACTID "@mozilla.org/toolkit/crash-reporter;1"
219 #include "nsIPrefService.h"
220 #endif
222 #ifdef MOZ_IPC
223 #include "base/command_line.h"
224 #endif
226 #include "mozilla/FunctionTimer.h"
228 #ifdef ANDROID
229 #include "AndroidBridge.h"
230 #endif
232 #ifdef WINCE
233 class WindowsMutex {
234 public:
235 WindowsMutex(const wchar_t *name) {
236 mHandle = CreateMutexW(0, FALSE, name);
239 ~WindowsMutex() {
240 Unlock();
241 CloseHandle(mHandle);
244 PRBool Lock(DWORD timeout = INFINITE) {
245 DWORD state = WaitForSingleObject(mHandle, timeout);
246 return state == WAIT_OBJECT_0;
249 void Unlock() {
250 if (mHandle)
251 ReleaseMutex(mHandle);
254 protected:
255 HANDLE mHandle;
257 #endif
259 extern void InstallSignalHandlers(const char *ProgramName);
260 #include "nsX11ErrorHandler.h"
262 #define FILE_COMPATIBILITY_INFO NS_LITERAL_CSTRING("compatibility.ini")
263 #define FILE_INVALIDATE_CACHES NS_LITERAL_CSTRING(".purgecaches")
265 int gArgc;
266 char **gArgv;
268 static const char gToolkitVersion[] = NS_STRINGIFY(GRE_MILESTONE);
269 static const char gToolkitBuildID[] = NS_STRINGIFY(GRE_BUILDID);
271 static int gRestartArgc;
272 static char **gRestartArgv;
274 #ifdef MOZ_WIDGET_QT
275 static int gQtOnlyArgc;
276 static char **gQtOnlyArgv;
277 #endif
279 #if defined(MOZ_WIDGET_GTK2)
280 #if defined(DEBUG) || defined(NS_BUILD_REFCNT_LOGGING) \
281 || defined(NS_TRACE_MALLOC)
282 #define CLEANUP_MEMORY 1
283 #define PANGO_ENABLE_BACKEND
284 #include <pango/pangofc-fontmap.h>
285 #endif
286 #include <gtk/gtk.h>
287 #ifdef MOZ_X11
288 #include <gdk/gdkx.h>
289 #endif /* MOZ_X11 */
290 #include "nsGTKToolkit.h"
291 #endif
293 // Save literal putenv string to environment variable.
294 static void
295 SaveToEnv(const char *putenv)
297 char *expr = strdup(putenv);
298 if (expr)
299 PR_SetEnv(expr);
300 // We intentionally leak |expr| here since it is required by PR_SetEnv.
303 // Save the given word to the specified environment variable.
304 static void
305 SaveWordToEnv(const char *name, const nsACString & word)
307 char *expr = PR_smprintf("%s=%s", name, PromiseFlatCString(word).get());
308 if (expr)
309 PR_SetEnv(expr);
310 // We intentionally leak |expr| here since it is required by PR_SetEnv.
313 // Save the path of the given file to the specified environment variable.
314 static void
315 SaveFileToEnv(const char *name, nsIFile *file)
317 #ifdef XP_WIN
318 nsAutoString path;
319 file->GetPath(path);
320 SetEnvironmentVariableW(NS_ConvertASCIItoUTF16(name).get(), path.get());
321 #else
322 nsCAutoString path;
323 file->GetNativePath(path);
324 SaveWordToEnv(name, path);
325 #endif
328 // Load the path of a file saved with SaveFileToEnv
329 static already_AddRefed<nsILocalFile>
330 GetFileFromEnv(const char *name)
332 nsresult rv;
333 nsILocalFile *file = nsnull;
335 #ifdef XP_WIN
336 WCHAR path[_MAX_PATH];
337 if (!GetEnvironmentVariableW(NS_ConvertASCIItoUTF16(name).get(),
338 path, _MAX_PATH))
339 return nsnull;
341 rv = NS_NewLocalFile(nsDependentString(path), PR_TRUE, &file);
342 if (NS_FAILED(rv))
343 return nsnull;
345 return file;
346 #else
347 const char *arg = PR_GetEnv(name);
348 if (!arg || !*arg)
349 return nsnull;
351 rv = NS_NewNativeLocalFile(nsDependentCString(arg), PR_TRUE, &file);
352 if (NS_FAILED(rv))
353 return nsnull;
355 return file;
356 #endif
359 // Save the path of the given word to the specified environment variable
360 // provided the environment variable does not have a value.
361 static void
362 SaveWordToEnvIfUnset(const char *name, const nsACString & word)
364 const char *val = PR_GetEnv(name);
365 if (!(val && *val))
366 SaveWordToEnv(name, word);
369 // Save the path of the given file to the specified environment variable
370 // provided the environment variable does not have a value.
371 static void
372 SaveFileToEnvIfUnset(const char *name, nsIFile *file)
374 const char *val = PR_GetEnv(name);
375 if (!(val && *val))
376 SaveFileToEnv(name, file);
379 static PRBool
380 strimatch(const char* lowerstr, const char* mixedstr)
382 while(*lowerstr) {
383 if (!*mixedstr) return PR_FALSE; // mixedstr is shorter
384 if (tolower(*mixedstr) != *lowerstr) return PR_FALSE; // no match
386 ++lowerstr;
387 ++mixedstr;
390 if (*mixedstr) return PR_FALSE; // lowerstr is shorter
392 return PR_TRUE;
396 * Output a string to the user. This method is really only meant to be used to
397 * output last-ditch error messages designed for developers NOT END USERS.
399 * @param isError
400 * Pass true to indicate severe errors.
401 * @param fmt
402 * printf-style format string followed by arguments.
404 static void Output(PRBool isError, const char *fmt, ... )
406 va_list ap;
407 va_start(ap, fmt);
409 #if defined(XP_WIN) && !MOZ_WINCONSOLE
410 char *msg = PR_vsmprintf(fmt, ap);
411 if (msg)
413 UINT flags = MB_OK;
414 if (isError)
415 flags |= MB_ICONERROR;
416 else
417 flags |= MB_ICONINFORMATION;
419 wchar_t wide_msg[1024];
420 MultiByteToWideChar(CP_ACP,
422 msg,
424 wide_msg,
425 sizeof(wide_msg) / sizeof(wchar_t));
427 MessageBoxW(NULL, wide_msg, L"XULRunner", flags);
428 PR_smprintf_free(msg);
430 #else
431 vfprintf(stderr, fmt, ap);
432 #endif
434 va_end(ap);
437 enum RemoteResult {
438 REMOTE_NOT_FOUND = 0,
439 REMOTE_FOUND = 1,
440 REMOTE_ARG_BAD = 2
443 enum ArgResult {
444 ARG_NONE = 0,
445 ARG_FOUND = 1,
446 ARG_BAD = 2 // you wanted a param, but there isn't one
449 static void RemoveArg(char **argv)
451 do {
452 *argv = *(argv + 1);
453 ++argv;
454 } while (*argv);
456 --gArgc;
460 * Check for a commandline flag. If the flag takes a parameter, the
461 * parameter is returned in aParam. Flags may be in the form -arg or
462 * --arg (or /arg on win32/OS2).
464 * @param aArg the parameter to check. Must be lowercase.
465 * @param aCheckOSInt if true returns ARG_BAD if the osint argument is present
466 * when aArg is also present.
467 * @param if non-null, the -arg <data> will be stored in this pointer. This is *not*
468 * allocated, but rather a pointer to the argv data.
470 static ArgResult
471 CheckArg(const char* aArg, PRBool aCheckOSInt = PR_FALSE, const char **aParam = nsnull, PRBool aRemArg = PR_TRUE)
473 char **curarg = gArgv + 1; // skip argv[0]
474 ArgResult ar = ARG_NONE;
476 while (*curarg) {
477 char *arg = curarg[0];
479 if (arg[0] == '-'
480 #if defined(XP_WIN) || defined(XP_OS2)
481 || *arg == '/'
482 #endif
484 ++arg;
485 if (*arg == '-')
486 ++arg;
488 if (strimatch(aArg, arg)) {
489 if (aRemArg)
490 RemoveArg(curarg);
491 if (!aParam) {
492 ar = ARG_FOUND;
493 break;
496 if (*curarg) {
497 if (**curarg == '-'
498 #if defined(XP_WIN) || defined(XP_OS2)
499 || **curarg == '/'
500 #endif
502 return ARG_BAD;
504 *aParam = *curarg;
505 if (aRemArg)
506 RemoveArg(curarg);
507 ar = ARG_FOUND;
508 break;
510 return ARG_BAD;
514 ++curarg;
517 if (aCheckOSInt && ar == ARG_FOUND) {
518 ArgResult arOSInt = CheckArg("osint");
519 if (arOSInt == ARG_FOUND) {
520 ar = ARG_BAD;
521 PR_fprintf(PR_STDERR, "Error: argument -osint is invalid\n");
525 return ar;
528 #if defined(XP_WIN)
530 * Check for a commandline flag from the windows shell and remove it from the
531 * argv used when restarting. Flags MUST be in the form -arg.
533 * @param aArg the parameter to check. Must be lowercase.
535 static ArgResult
536 CheckArgShell(const char* aArg)
538 char **curarg = gRestartArgv + 1; // skip argv[0]
540 while (*curarg) {
541 char *arg = curarg[0];
543 if (arg[0] == '-') {
544 ++arg;
546 if (strimatch(aArg, arg)) {
547 do {
548 *curarg = *(curarg + 1);
549 ++curarg;
550 } while (*curarg);
552 --gRestartArgc;
554 return ARG_FOUND;
558 ++curarg;
561 return ARG_NONE;
565 * Enabled Native App Support to process DDE messages when the app needs to
566 * restart and the app has been launched by the Windows shell to open an url.
567 * When aWait is false this will process the DDE events manually. This prevents
568 * Windows from displaying an error message due to the DDE message not being
569 * acknowledged.
571 static void
572 ProcessDDE(nsINativeAppSupport* aNative, PRBool aWait)
574 // When the app is launched by the windows shell the windows shell
575 // expects the app to be available for DDE messages and if it isn't
576 // windows displays an error dialog. To prevent the error the DDE server
577 // is enabled and pending events are processed when the app needs to
578 // restart after it was launched by the shell with the requestpending
579 // argument. The requestpending pending argument is removed to
580 // differentiate it from being launched when an app restart is not
581 // required.
582 ArgResult ar;
583 ar = CheckArgShell("requestpending");
584 if (ar == ARG_FOUND) {
585 aNative->Enable(); // enable win32 DDE responses
586 if (aWait) {
587 nsIThread *thread = NS_GetCurrentThread();
588 // This is just a guesstimate based on testing different values.
589 // If count is 8 or less windows will display an error dialog.
590 PRInt32 count = 20;
591 while(--count >= 0) {
592 NS_ProcessNextEvent(thread);
593 PR_Sleep(PR_MillisecondsToInterval(1));
598 #endif
600 PRBool gSafeMode = PR_FALSE;
603 * The nsXULAppInfo object implements nsIFactory so that it can be its own
604 * singleton.
606 class nsXULAppInfo : public nsIXULAppInfo,
607 #ifdef XP_WIN
608 public nsIWinAppHelper,
609 #endif
610 #ifdef MOZ_CRASHREPORTER
611 public nsICrashReporter,
612 #endif
613 public nsIXULRuntime
616 public:
617 NS_DECL_ISUPPORTS_INHERITED
618 NS_DECL_NSIXULAPPINFO
619 NS_DECL_NSIXULRUNTIME
620 #ifdef MOZ_CRASHREPORTER
621 NS_DECL_NSICRASHREPORTER
622 #endif
623 #ifdef XP_WIN
624 NS_DECL_NSIWINAPPHELPER
625 #endif
628 NS_INTERFACE_MAP_BEGIN(nsXULAppInfo)
629 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXULRuntime)
630 NS_INTERFACE_MAP_ENTRY(nsIXULRuntime)
631 #ifdef XP_WIN
632 NS_INTERFACE_MAP_ENTRY(nsIWinAppHelper)
633 #endif
634 #ifdef MOZ_CRASHREPORTER
635 NS_INTERFACE_MAP_ENTRY(nsICrashReporter)
636 #endif
637 NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIXULAppInfo, gAppData)
638 NS_INTERFACE_MAP_END
640 NS_IMETHODIMP_(nsrefcnt)
641 nsXULAppInfo::AddRef()
643 return 1;
646 NS_IMETHODIMP_(nsrefcnt)
647 nsXULAppInfo::Release()
649 return 1;
652 NS_IMETHODIMP
653 nsXULAppInfo::GetVendor(nsACString& aResult)
655 aResult.Assign(gAppData->vendor);
657 return NS_OK;
660 NS_IMETHODIMP
661 nsXULAppInfo::GetName(nsACString& aResult)
663 aResult.Assign(gAppData->name);
665 return NS_OK;
668 NS_IMETHODIMP
669 nsXULAppInfo::GetID(nsACString& aResult)
671 aResult.Assign(gAppData->ID);
673 return NS_OK;
676 NS_IMETHODIMP
677 nsXULAppInfo::GetVersion(nsACString& aResult)
679 aResult.Assign(gAppData->version);
681 return NS_OK;
684 NS_IMETHODIMP
685 nsXULAppInfo::GetPlatformVersion(nsACString& aResult)
687 aResult.Assign(gToolkitVersion);
689 return NS_OK;
692 NS_IMETHODIMP
693 nsXULAppInfo::GetAppBuildID(nsACString& aResult)
695 aResult.Assign(gAppData->buildID);
697 return NS_OK;
700 NS_IMETHODIMP
701 nsXULAppInfo::GetPlatformBuildID(nsACString& aResult)
703 aResult.Assign(gToolkitBuildID);
705 return NS_OK;
708 NS_IMETHODIMP
709 nsXULAppInfo::GetLogConsoleErrors(PRBool *aResult)
711 *aResult = gLogConsoleErrors;
712 return NS_OK;
715 NS_IMETHODIMP
716 nsXULAppInfo::SetLogConsoleErrors(PRBool aValue)
718 gLogConsoleErrors = aValue;
719 return NS_OK;
722 NS_IMETHODIMP
723 nsXULAppInfo::GetInSafeMode(PRBool *aResult)
725 *aResult = gSafeMode;
726 return NS_OK;
729 NS_IMETHODIMP
730 nsXULAppInfo::GetOS(nsACString& aResult)
732 aResult.AssignLiteral(OS_TARGET);
733 return NS_OK;
736 NS_IMETHODIMP
737 nsXULAppInfo::GetXPCOMABI(nsACString& aResult)
739 #ifdef TARGET_XPCOM_ABI
740 aResult.AssignLiteral(TARGET_XPCOM_ABI);
741 return NS_OK;
742 #else
743 return NS_ERROR_NOT_AVAILABLE;
744 #endif
747 NS_IMETHODIMP
748 nsXULAppInfo::GetWidgetToolkit(nsACString& aResult)
750 aResult.AssignLiteral(MOZ_WIDGET_TOOLKIT);
751 return NS_OK;
754 // Ensure that the GeckoProcessType enum, defined in xpcom/build/nsXULAppAPI.h,
755 // is synchronized with the const unsigned longs defined in
756 // xpcom/system/nsIXULRuntime.idl.
757 #define SYNC_ENUMS(a,b) \
758 PR_STATIC_ASSERT(nsIXULRuntime::PROCESS_TYPE_ ## a == \
759 static_cast<int>(GeckoProcessType_ ## b));
761 SYNC_ENUMS(DEFAULT, Default)
762 SYNC_ENUMS(PLUGIN, Plugin)
763 SYNC_ENUMS(CONTENT, Content)
764 SYNC_ENUMS(JETPACK, Jetpack)
765 SYNC_ENUMS(IPDLUNITTEST, IPDLUnitTest)
767 // .. and ensure that that is all of them:
768 PR_STATIC_ASSERT(GeckoProcessType_IPDLUnitTest + 1 == GeckoProcessType_End);
770 NS_IMETHODIMP
771 nsXULAppInfo::GetProcessType(PRUint32* aResult)
773 NS_ENSURE_ARG_POINTER(aResult);
774 *aResult = XRE_GetProcessType();
775 return NS_OK;
778 NS_IMETHODIMP
779 nsXULAppInfo::EnsureContentProcess()
781 #ifdef MOZ_IPC
782 if (XRE_GetProcessType() != GeckoProcessType_Default)
783 return NS_ERROR_NOT_AVAILABLE;
785 ContentParent* c = ContentParent::GetSingleton();
786 if (!c)
787 return NS_ERROR_NOT_AVAILABLE;
788 return NS_OK;
789 #else
790 return NS_ERROR_NOT_AVAILABLE;
791 #endif
794 NS_IMETHODIMP
795 nsXULAppInfo::InvalidateCachesOnRestart()
797 nsCOMPtr<nsIFile> file;
798 nsresult rv = NS_GetSpecialDirectory(NS_APP_PROFILE_DIR_STARTUP,
799 getter_AddRefs(file));
800 if (NS_FAILED(rv))
801 return rv;
802 if (!file)
803 return NS_ERROR_NOT_AVAILABLE;
805 file->AppendNative(FILE_COMPATIBILITY_INFO);
807 nsCOMPtr<nsILocalFile> localFile(do_QueryInterface(file));
808 nsINIParser parser;
809 rv = parser.Init(localFile);
810 if (NS_FAILED(rv)) {
811 // This fails if compatibility.ini is not there, so we'll
812 // flush the caches on the next restart anyways.
813 return NS_OK;
816 nsCAutoString buf;
817 rv = parser.GetString("Compatibility", "InvalidateCaches", buf);
819 if (NS_FAILED(rv)) {
820 PRFileDesc *fd = nsnull;
821 localFile->OpenNSPRFileDesc(PR_RDWR | PR_APPEND, 0600, &fd);
822 if (!fd) {
823 NS_ERROR("could not create output stream");
824 return NS_ERROR_NOT_AVAILABLE;
826 static const char kInvalidationHeader[] = NS_LINEBREAK "InvalidateCaches=1" NS_LINEBREAK;
827 rv = PR_Write(fd, kInvalidationHeader, sizeof(kInvalidationHeader) - 1);
828 PR_Close(fd);
830 if (NS_FAILED(rv))
831 return rv;
833 return NS_OK;
836 #ifdef XP_WIN
837 // Matches the enum in WinNT.h for the Vista SDK but renamed so that we can
838 // safely build with the Vista SDK and without it.
839 typedef enum
841 VistaTokenElevationTypeDefault = 1,
842 VistaTokenElevationTypeFull,
843 VistaTokenElevationTypeLimited
844 } VISTA_TOKEN_ELEVATION_TYPE;
846 // avoid collision with TokeElevationType enum in WinNT.h
847 // of the Vista SDK
848 #define VistaTokenElevationType static_cast< TOKEN_INFORMATION_CLASS >( 18 )
850 NS_IMETHODIMP
851 nsXULAppInfo::GetUserCanElevate(PRBool *aUserCanElevate)
853 #ifdef WINCE
854 *aUserCanElevate = PR_FALSE;
855 return NS_OK;
856 #else
857 HANDLE hToken;
859 VISTA_TOKEN_ELEVATION_TYPE elevationType;
860 DWORD dwSize;
862 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken) ||
863 !GetTokenInformation(hToken, VistaTokenElevationType, &elevationType,
864 sizeof(elevationType), &dwSize)) {
865 *aUserCanElevate = PR_FALSE;
867 else {
868 // The possible values returned for elevationType and their meanings are:
869 // TokenElevationTypeDefault: The token does not have a linked token
870 // (e.g. UAC disabled or a standard user, so they can't be elevated)
871 // TokenElevationTypeFull: The token is linked to an elevated token
872 // (e.g. UAC is enabled and the user is already elevated so they can't
873 // be elevated again)
874 // TokenElevationTypeLimited: The token is linked to a limited token
875 // (e.g. UAC is enabled and the user is not elevated, so they can be
876 // elevated)
877 *aUserCanElevate = (elevationType == VistaTokenElevationTypeLimited);
880 if (hToken)
881 CloseHandle(hToken);
883 return NS_OK;
884 #endif // WINCE
886 #endif
888 #ifdef MOZ_CRASHREPORTER
889 NS_IMETHODIMP
890 nsXULAppInfo::GetEnabled(PRBool *aEnabled)
892 *aEnabled = CrashReporter::GetEnabled();
893 return NS_OK;
896 NS_IMETHODIMP
897 nsXULAppInfo::SetEnabled(PRBool aEnabled)
899 if (aEnabled) {
900 if (CrashReporter::GetEnabled())
901 // no point in erroring for double-enabling
902 return NS_OK;
904 nsCOMPtr<nsILocalFile> xreDirectory;
905 if (gAppData) {
906 xreDirectory = gAppData->xreDirectory;
908 else {
909 // We didn't get started through XRE_Main, probably
910 nsCOMPtr<nsIFile> greDir;
911 NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(greDir));
912 if (!greDir)
913 return NS_ERROR_FAILURE;
915 xreDirectory = do_QueryInterface(greDir);
916 if (!xreDirectory)
917 return NS_ERROR_FAILURE;
919 return CrashReporter::SetExceptionHandler(xreDirectory, true);
921 else {
922 if (!CrashReporter::GetEnabled())
923 // no point in erroring for double-disabling
924 return NS_OK;
926 return CrashReporter::UnsetExceptionHandler();
930 NS_IMETHODIMP
931 nsXULAppInfo::GetServerURL(nsIURL** aServerURL)
933 if (!CrashReporter::GetEnabled())
934 return NS_ERROR_NOT_INITIALIZED;
936 nsCAutoString data;
937 if (!CrashReporter::GetServerURL(data)) {
938 return NS_ERROR_FAILURE;
940 nsCOMPtr<nsIURI> uri;
941 NS_NewURI(getter_AddRefs(uri), data);
942 if (!uri)
943 return NS_ERROR_FAILURE;
945 nsCOMPtr<nsIURL> url;
946 url = do_QueryInterface(uri);
947 NS_ADDREF(*aServerURL = url);
949 return NS_OK;
952 NS_IMETHODIMP
953 nsXULAppInfo::SetServerURL(nsIURL* aServerURL)
955 PRBool schemeOk;
956 // only allow https or http URLs
957 nsresult rv = aServerURL->SchemeIs("https", &schemeOk);
958 NS_ENSURE_SUCCESS(rv, rv);
959 if (!schemeOk) {
960 rv = aServerURL->SchemeIs("http", &schemeOk);
961 NS_ENSURE_SUCCESS(rv, rv);
963 if (!schemeOk)
964 return NS_ERROR_INVALID_ARG;
966 nsCAutoString spec;
967 rv = aServerURL->GetSpec(spec);
968 NS_ENSURE_SUCCESS(rv, rv);
970 return CrashReporter::SetServerURL(spec);
973 NS_IMETHODIMP
974 nsXULAppInfo::GetMinidumpPath(nsILocalFile** aMinidumpPath)
976 if (!CrashReporter::GetEnabled())
977 return NS_ERROR_NOT_INITIALIZED;
979 nsAutoString path;
980 if (!CrashReporter::GetMinidumpPath(path))
981 return NS_ERROR_FAILURE;
983 nsresult rv = NS_NewLocalFile(path, PR_FALSE, aMinidumpPath);
984 NS_ENSURE_SUCCESS(rv, rv);
985 return NS_OK;
988 NS_IMETHODIMP
989 nsXULAppInfo::SetMinidumpPath(nsILocalFile* aMinidumpPath)
991 nsAutoString path;
992 nsresult rv = aMinidumpPath->GetPath(path);
993 NS_ENSURE_SUCCESS(rv, rv);
994 return CrashReporter::SetMinidumpPath(path);
997 NS_IMETHODIMP
998 nsXULAppInfo::AnnotateCrashReport(const nsACString& key,
999 const nsACString& data)
1001 return CrashReporter::AnnotateCrashReport(key, data);
1004 NS_IMETHODIMP
1005 nsXULAppInfo::AppendAppNotesToCrashReport(const nsACString& data)
1007 return CrashReporter::AppendAppNotesToCrashReport(data);
1010 NS_IMETHODIMP
1011 nsXULAppInfo::WriteMinidumpForException(void* aExceptionInfo)
1013 #ifdef XP_WIN32
1014 return CrashReporter::WriteMinidumpForException(static_cast<EXCEPTION_POINTERS*>(aExceptionInfo));
1015 #else
1016 return NS_ERROR_NOT_IMPLEMENTED;
1017 #endif
1020 NS_IMETHODIMP
1021 nsXULAppInfo::AppendObjCExceptionInfoToAppNotes(void* aException)
1023 #ifdef XP_MACOSX
1024 return CrashReporter::AppendObjCExceptionInfoToAppNotes(aException);
1025 #else
1026 return NS_ERROR_NOT_IMPLEMENTED;
1027 #endif
1030 NS_IMETHODIMP
1031 nsXULAppInfo::GetSubmitReports(PRBool* aEnabled)
1033 return CrashReporter::GetSubmitReports(aEnabled);
1036 NS_IMETHODIMP
1037 nsXULAppInfo::SetSubmitReports(PRBool aEnabled)
1039 return CrashReporter::SetSubmitReports(aEnabled);
1042 #endif
1044 static const nsXULAppInfo kAppInfo;
1045 static nsresult AppInfoConstructor(nsISupports* aOuter,
1046 REFNSIID aIID, void **aResult)
1048 NS_ENSURE_NO_AGGREGATION(aOuter);
1050 return const_cast<nsXULAppInfo*>(&kAppInfo)->
1051 QueryInterface(aIID, aResult);
1054 PRBool gLogConsoleErrors
1055 #ifdef DEBUG
1056 = PR_TRUE;
1057 #else
1058 = PR_FALSE;
1059 #endif
1061 #define NS_ENSURE_TRUE_LOG(x, ret) \
1062 PR_BEGIN_MACRO \
1063 if (NS_UNLIKELY(!(x))) { \
1064 NS_WARNING("NS_ENSURE_TRUE(" #x ") failed"); \
1065 gLogConsoleErrors = PR_TRUE; \
1066 return ret; \
1068 PR_END_MACRO
1070 #define NS_ENSURE_SUCCESS_LOG(res, ret) \
1071 NS_ENSURE_TRUE_LOG(NS_SUCCEEDED(res), ret)
1074 * Because we're starting/stopping XPCOM several times in different scenarios,
1075 * this class is a stack-based critter that makes sure that XPCOM is shut down
1076 * during early returns.
1079 class ScopedXPCOMStartup
1081 public:
1082 ScopedXPCOMStartup() :
1083 mServiceManager(nsnull) { }
1084 ~ScopedXPCOMStartup();
1086 nsresult Initialize();
1087 nsresult SetWindowCreator(nsINativeAppSupport* native);
1089 static nsresult CreateAppSupport(nsISupports* aOuter, REFNSIID aIID, void** aResult);
1091 private:
1092 nsIServiceManager* mServiceManager;
1093 static nsINativeAppSupport* gNativeAppSupport;
1096 ScopedXPCOMStartup::~ScopedXPCOMStartup()
1098 NS_IF_RELEASE(gNativeAppSupport);
1100 if (mServiceManager) {
1101 #ifdef XP_MACOSX
1102 // On OS X, we need a pool to catch cocoa objects that are autoreleased
1103 // during teardown.
1104 mozilla::MacAutoreleasePool pool;
1105 #endif
1107 nsCOMPtr<nsIAppStartup> appStartup (do_GetService(NS_APPSTARTUP_CONTRACTID));
1108 if (appStartup)
1109 appStartup->DestroyHiddenWindow();
1111 gDirServiceProvider->DoShutdown();
1113 WriteConsoleLog();
1115 NS_ShutdownXPCOM(mServiceManager);
1116 mServiceManager = nsnull;
1120 // {95d89e3e-a169-41a3-8e56-719978e15b12}
1121 #define APPINFO_CID \
1122 { 0x95d89e3e, 0xa169, 0x41a3, { 0x8e, 0x56, 0x71, 0x99, 0x78, 0xe1, 0x5b, 0x12 } }
1124 // {0C4A446C-EE82-41f2-8D04-D366D2C7A7D4}
1125 static const nsCID kNativeAppSupportCID =
1126 { 0xc4a446c, 0xee82, 0x41f2, { 0x8d, 0x4, 0xd3, 0x66, 0xd2, 0xc7, 0xa7, 0xd4 } };
1128 // {5F5E59CE-27BC-47eb-9D1F-B09CA9049836}
1129 static const nsCID kProfileServiceCID =
1130 { 0x5f5e59ce, 0x27bc, 0x47eb, { 0x9d, 0x1f, 0xb0, 0x9c, 0xa9, 0x4, 0x98, 0x36 } };
1132 static already_AddRefed<nsIFactory>
1133 ProfileServiceFactoryConstructor(const mozilla::Module& module, const mozilla::Module::CIDEntry& entry)
1135 nsCOMPtr<nsIFactory> factory;
1136 NS_NewToolkitProfileFactory(getter_AddRefs(factory));
1137 return factory.forget();
1140 NS_DEFINE_NAMED_CID(APPINFO_CID);
1142 static const mozilla::Module::CIDEntry kXRECIDs[] = {
1143 { &kAPPINFO_CID, false, NULL, AppInfoConstructor },
1144 { &kProfileServiceCID, false, ProfileServiceFactoryConstructor, NULL },
1145 { &kNativeAppSupportCID, false, NULL, ScopedXPCOMStartup::CreateAppSupport },
1146 { NULL }
1149 static const mozilla::Module::ContractIDEntry kXREContracts[] = {
1150 { XULAPPINFO_SERVICE_CONTRACTID, &kAPPINFO_CID },
1151 { XULRUNTIME_SERVICE_CONTRACTID, &kAPPINFO_CID },
1152 #ifdef MOZ_CRASHREPORTER
1153 { NS_CRASHREPORTER_CONTRACTID, &kAPPINFO_CID },
1154 #endif
1155 { NS_PROFILESERVICE_CONTRACTID, &kProfileServiceCID },
1156 { NS_NATIVEAPPSUPPORT_CONTRACTID, &kNativeAppSupportCID },
1157 { NULL }
1160 static const mozilla::Module kXREModule = {
1161 mozilla::Module::kVersion,
1162 kXRECIDs,
1163 kXREContracts
1166 NSMODULE_DEFN(Apprunner) = &kXREModule;
1168 nsresult
1169 ScopedXPCOMStartup::Initialize()
1171 NS_ASSERTION(gDirServiceProvider, "Should not get here!");
1173 nsresult rv;
1175 #ifndef MOZ_ENABLE_LIBXUL
1176 #ifndef _BUILD_STATIC_BIN
1177 XRE_AddStaticComponent(&kXREModule);
1178 #else
1179 for (const mozilla::Module *const *staticModules = kPStaticModules;
1180 *staticModules; ++staticModules)
1181 XRE_AddStaticComponent(*staticModules);
1182 #endif
1183 #endif
1185 rv = NS_InitXPCOM2(&mServiceManager, gDirServiceProvider->GetAppDir(),
1186 gDirServiceProvider);
1187 if (NS_FAILED(rv)) {
1188 NS_ERROR("Couldn't start xpcom!");
1189 mServiceManager = nsnull;
1191 else {
1192 nsCOMPtr<nsIComponentRegistrar> reg =
1193 do_QueryInterface(mServiceManager);
1194 NS_ASSERTION(reg, "Service Manager doesn't QI to Registrar.");
1197 return rv;
1201 * This is a little factory class that serves as a singleton-service-factory
1202 * for the nativeappsupport object.
1204 class nsSingletonFactory : public nsIFactory
1206 public:
1207 NS_DECL_ISUPPORTS
1208 NS_DECL_NSIFACTORY
1210 nsSingletonFactory(nsISupports* aSingleton);
1211 ~nsSingletonFactory() { }
1213 private:
1214 nsCOMPtr<nsISupports> mSingleton;
1217 nsSingletonFactory::nsSingletonFactory(nsISupports* aSingleton)
1218 : mSingleton(aSingleton)
1220 NS_ASSERTION(mSingleton, "Singleton was null!");
1223 NS_IMPL_ISUPPORTS1(nsSingletonFactory, nsIFactory)
1225 NS_IMETHODIMP
1226 nsSingletonFactory::CreateInstance(nsISupports* aOuter,
1227 const nsIID& aIID,
1228 void* *aResult)
1230 NS_ENSURE_NO_AGGREGATION(aOuter);
1232 return mSingleton->QueryInterface(aIID, aResult);
1235 NS_IMETHODIMP
1236 nsSingletonFactory::LockFactory(PRBool)
1238 return NS_OK;
1242 * Set our windowcreator on the WindowWatcher service.
1244 nsresult
1245 ScopedXPCOMStartup::SetWindowCreator(nsINativeAppSupport* native)
1247 NS_TIME_FUNCTION;
1248 nsresult rv;
1250 NS_IF_ADDREF(gNativeAppSupport = native);
1252 // Inform the chrome registry about OS accessibility
1253 nsCOMPtr<nsIToolkitChromeRegistry> cr =
1254 mozilla::services::GetToolkitChromeRegistryService();
1255 NS_TIME_FUNCTION_MARK("Got ToolkitChromeRegistry service");
1257 if (cr)
1258 cr->CheckForOSAccessibility();
1260 NS_TIME_FUNCTION_MARK("OS Accessibility check");
1262 nsCOMPtr<nsIWindowCreator> creator (do_GetService(NS_APPSTARTUP_CONTRACTID));
1263 if (!creator) return NS_ERROR_UNEXPECTED;
1265 NS_TIME_FUNCTION_MARK("Got AppStartup service");
1267 nsCOMPtr<nsIWindowWatcher> wwatch
1268 (do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv));
1269 NS_ENSURE_SUCCESS(rv, rv);
1271 NS_TIME_FUNCTION_MARK("Got WindowWatcher service");
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 " --no-xshm Don't use X shared memory extension\n"
1336 " --xim-preedit=STYLE\n"
1337 " --xim-status=STYLE\n");
1338 #endif
1339 #ifdef XP_UNIX
1340 printf(" --g-fatal-warnings Make all warnings fatal\n"
1341 "\n%s options\n", gAppData->name);
1342 #endif
1344 printf(" -h or -help Print this message.\n"
1345 " -v or -version Print %s version.\n"
1346 " -P <profile> Start with <profile>.\n"
1347 " -migration Start with migration wizard.\n"
1348 " -ProfileManager Start with ProfileManager.\n"
1349 " -no-remote Open new instance, not a new window in running instance.\n"
1350 " -UILocale <locale> Start with <locale> resources as UI Locale.\n"
1351 " -safe-mode Disables extensions and themes for this session.\n", gAppData->name);
1353 #if defined(XP_WIN) || defined(XP_OS2)
1354 printf(" -console Start %s with a debugging console.\n", gAppData->name);
1355 #endif
1357 // this works, but only after the components have registered. so if you drop in a new command line handler, -help
1358 // won't not until the second run.
1359 // out of the bug, because we ship a component.reg file, it works correctly.
1360 DumpArbitraryHelp();
1363 #ifdef DEBUG_warren
1364 #ifdef XP_WIN
1365 #define _CRTDBG_MAP_ALLOC
1366 #include <crtdbg.h>
1367 #endif
1368 #endif
1370 #if defined(FREEBSD)
1371 // pick up fpsetmask prototype.
1372 #include <ieeefp.h>
1373 #endif
1375 static inline void
1376 DumpVersion()
1378 printf("%s %s %s",
1379 gAppData->vendor ? gAppData->vendor : "", gAppData->name, gAppData->version);
1380 if (gAppData->copyright)
1381 printf(", %s", gAppData->copyright);
1382 printf("\n");
1385 #ifdef MOZ_ENABLE_XREMOTE
1386 // use int here instead of a PR type since it will be returned
1387 // from main - just to keep types consistent
1388 static int
1389 HandleRemoteArgument(const char* remote, const char* aDesktopStartupID)
1391 nsresult rv;
1392 ArgResult ar;
1394 const char *profile = 0;
1395 nsCAutoString program(gAppData->name);
1396 ToLowerCase(program);
1397 const char *username = getenv("LOGNAME");
1399 ar = CheckArg("p", PR_FALSE, &profile);
1400 if (ar == ARG_BAD) {
1401 PR_fprintf(PR_STDERR, "Error: argument -p requires a profile name\n");
1402 return 1;
1405 const char *temp = nsnull;
1406 ar = CheckArg("a", PR_FALSE, &temp);
1407 if (ar == ARG_BAD) {
1408 PR_fprintf(PR_STDERR, "Error: argument -a requires an application name\n");
1409 return 1;
1410 } else if (ar == ARG_FOUND) {
1411 program.Assign(temp);
1414 ar = CheckArg("u", PR_FALSE, &username);
1415 if (ar == ARG_BAD) {
1416 PR_fprintf(PR_STDERR, "Error: argument -u requires a username\n");
1417 return 1;
1420 XRemoteClient client;
1421 rv = client.Init();
1422 if (NS_FAILED(rv)) {
1423 PR_fprintf(PR_STDERR, "Error: Failed to connect to X server.\n");
1424 return 1;
1427 nsXPIDLCString response;
1428 PRBool success = PR_FALSE;
1429 rv = client.SendCommand(program.get(), username, profile, remote,
1430 aDesktopStartupID, getter_Copies(response), &success);
1431 // did the command fail?
1432 if (NS_FAILED(rv)) {
1433 PR_fprintf(PR_STDERR, "Error: Failed to send command: %s\n",
1434 response ? response.get() : "No response included");
1435 return 1;
1438 if (!success) {
1439 PR_fprintf(PR_STDERR, "Error: No running window found\n");
1440 return 2;
1443 return 0;
1446 static RemoteResult
1447 RemoteCommandLine(const char* aDesktopStartupID)
1449 nsresult rv;
1450 ArgResult ar;
1452 nsCAutoString program(gAppData->name);
1453 ToLowerCase(program);
1454 const char *username = getenv("LOGNAME");
1456 const char *temp = nsnull;
1457 ar = CheckArg("a", PR_TRUE, &temp);
1458 if (ar == ARG_BAD) {
1459 PR_fprintf(PR_STDERR, "Error: argument -a requires an application name\n");
1460 return REMOTE_ARG_BAD;
1461 } else if (ar == ARG_FOUND) {
1462 program.Assign(temp);
1465 ar = CheckArg("u", PR_TRUE, &username);
1466 if (ar == ARG_BAD) {
1467 PR_fprintf(PR_STDERR, "Error: argument -u requires a username\n");
1468 return REMOTE_ARG_BAD;
1471 XRemoteClient client;
1472 rv = client.Init();
1473 if (NS_FAILED(rv))
1474 return REMOTE_NOT_FOUND;
1476 nsXPIDLCString response;
1477 PRBool success = PR_FALSE;
1478 rv = client.SendCommandLine(program.get(), username, nsnull,
1479 gArgc, gArgv, aDesktopStartupID,
1480 getter_Copies(response), &success);
1481 // did the command fail?
1482 if (NS_FAILED(rv) || !success)
1483 return REMOTE_NOT_FOUND;
1485 return REMOTE_FOUND;
1487 #endif // MOZ_ENABLE_XREMOTE
1489 #ifdef XP_MACOSX
1490 static char const *gBinaryPath;
1491 #endif
1493 nsresult
1494 XRE_GetBinaryPath(const char* argv0, nsILocalFile* *aResult)
1496 nsresult rv;
1497 nsCOMPtr<nsILocalFile> lf;
1499 // We need to use platform-specific hackery to find the
1500 // path of this executable. This is copied, with some modifications, from
1501 // nsGREDirServiceProvider.cpp
1503 #ifdef XP_WIN
1504 PRUnichar exePath[MAXPATHLEN];
1506 if (!::GetModuleFileNameW(0, exePath, MAXPATHLEN))
1507 return NS_ERROR_FAILURE;
1509 rv = NS_NewLocalFile(nsDependentString(exePath), PR_TRUE,
1510 getter_AddRefs(lf));
1511 if (NS_FAILED(rv))
1512 return rv;
1514 #elif defined(XP_MACOSX)
1515 if (gBinaryPath)
1516 return NS_NewNativeLocalFile(nsDependentCString(gBinaryPath), PR_FALSE,
1517 aResult);
1519 NS_NewNativeLocalFile(EmptyCString(), PR_TRUE, getter_AddRefs(lf));
1520 nsCOMPtr<nsILocalFileMac> lfm (do_QueryInterface(lf));
1521 if (!lfm)
1522 return NS_ERROR_FAILURE;
1524 // Works even if we're not bundled.
1525 CFBundleRef appBundle = CFBundleGetMainBundle();
1526 if (!appBundle)
1527 return NS_ERROR_FAILURE;
1529 CFURLRef executableURL = CFBundleCopyExecutableURL(appBundle);
1530 if (!executableURL)
1531 return NS_ERROR_FAILURE;
1532 rv = lfm->InitWithCFURL(executableURL);
1533 CFRelease(executableURL);
1534 if (NS_FAILED(rv))
1535 return rv;
1537 // Callers expect a normalized path.
1538 lfm->Normalize();
1540 #elif defined(XP_UNIX)
1541 struct stat fileStat;
1542 char exePath[MAXPATHLEN];
1543 char tmpPath[MAXPATHLEN];
1545 rv = NS_ERROR_FAILURE;
1547 // on unix, there is no official way to get the path of the current binary.
1548 // instead of using the MOZILLA_FIVE_HOME hack, which doesn't scale to
1549 // multiple applications, we will try a series of techniques:
1551 // 1) look for /proc/<pid>/exe which is a symlink to the executable on newer
1552 // Linux kernels
1553 // 2) use realpath() on argv[0], which works unless we're loaded from the
1554 // PATH
1555 // 3) manually walk through the PATH and look for ourself
1556 // 4) give up
1558 // #ifdef __linux__
1559 // Commented out because it used to not work because it used to not deal
1560 // with readlink not null-terminating the buffer.
1561 #if 0
1562 int r = readlink("/proc/self/exe", exePath, MAXPATHLEN);
1564 if (r > 0 && r < MAXPATHLEN) {
1565 exePath[r] = '\0';
1566 if (stat(exePath, &fileStat) == 0) {
1567 rv = NS_OK;
1571 #endif
1572 if (NS_FAILED(rv) &&
1573 realpath(argv0, exePath) && stat(exePath, &fileStat) == 0) {
1574 rv = NS_OK;
1577 if (NS_FAILED(rv)) {
1578 const char *path = getenv("PATH");
1579 if (!path)
1580 return NS_ERROR_FAILURE;
1582 char *pathdup = strdup(path);
1583 if (!pathdup)
1584 return NS_ERROR_OUT_OF_MEMORY;
1586 PRBool found = PR_FALSE;
1587 char *newStr = pathdup;
1588 char *token;
1589 while ( (token = nsCRT::strtok(newStr, ":", &newStr)) ) {
1590 sprintf(tmpPath, "%s/%s", token, argv0);
1591 if (realpath(tmpPath, exePath) && stat(exePath, &fileStat) == 0) {
1592 found = PR_TRUE;
1593 break;
1596 free(pathdup);
1597 if (!found)
1598 return NS_ERROR_FAILURE;
1601 rv = NS_NewNativeLocalFile(nsDependentCString(exePath), PR_TRUE,
1602 getter_AddRefs(lf));
1603 if (NS_FAILED(rv))
1604 return rv;
1606 #elif defined(XP_OS2)
1607 PPIB ppib;
1608 PTIB ptib;
1609 char exePath[MAXPATHLEN];
1611 DosGetInfoBlocks( &ptib, &ppib);
1612 DosQueryModuleName( ppib->pib_hmte, MAXPATHLEN, exePath);
1613 rv = NS_NewNativeLocalFile(nsDependentCString(exePath), PR_TRUE,
1614 getter_AddRefs(lf));
1615 if (NS_FAILED(rv))
1616 return rv;
1618 #elif defined(XP_BEOS)
1619 int32 cookie = 0;
1620 image_info info;
1622 if(get_next_image_info(0, &cookie, &info) != B_OK)
1623 return NS_ERROR_FAILURE;
1625 rv = NS_NewNativeLocalFile(nsDependentCString(info.name), PR_TRUE,
1626 getter_AddRefs(lf));
1627 if (NS_FAILED(rv))
1628 return rv;
1630 #else
1631 #error Oops, you need platform-specific code here
1632 #endif
1634 NS_ADDREF(*aResult = lf);
1635 return NS_OK;
1638 #define NS_ERROR_LAUNCHED_CHILD_PROCESS NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_PROFILE, 200)
1640 #ifdef XP_WIN
1641 #include "nsWindowsRestart.cpp"
1642 #include <shellapi.h>
1643 #endif
1645 #if defined(XP_OS2) && (__KLIBC__ == 0 && __KLIBC_MINOR__ >= 6) // broken kLibc
1646 // Copy the environment maintained by the C library into an ASCIIZ array
1647 // that can be used to pass it on to the OS/2 Dos* APIs (which otherwise
1648 // don't know anything about the stuff set by PR_SetEnv() or setenv()).
1649 char *createEnv()
1651 // just allocate the maximum amount (24 kB = 0x60000 bytes), to be able to
1652 // copy the existing environment
1653 char *env = (char *)calloc(0x6000, sizeof(char));
1654 if (!env) {
1655 return NULL;
1658 // walk along the environ string array of the C library and copy
1659 // everything (that fits) into the output environment array, leaving
1660 // null bytes between the entries
1661 char *penv = env; // movable pointer to result environment ASCIIZ array
1662 int i = 0, space = 0x6000;
1663 while (environ[i] && environ[i][0]) {
1664 int len = strlen(environ[i]);
1665 if (space - len <= 0) {
1666 break;
1668 strcpy(penv, environ[i]);
1669 i++; // next environment variable
1670 penv += len + 1; // jump to after next null byte
1671 space -= len - 1; // subtract consumed length from usable space
1674 return env;
1677 // OS2LaunchChild() is there to replace _execv() which is broken in the C
1678 // runtime library that comes with GCC 3.3.5 on OS/2. It uses createEnv()
1679 // to copy the process environment and add necessary variables
1681 // returns -1 on failure and 0 on success
1682 int OS2LaunchChild(const char *aExePath, int aArgc, char **aArgv)
1684 // find total length of aArgv
1685 int len = 0;
1686 for (int i = 0; i < aArgc; i++) {
1687 len += strlen(aArgv[i]) + 1; // plus space in between
1689 len++; // leave space for null byte at end
1690 // allocate enough space for all strings and nulls,
1691 // calloc helpfully initializes to null
1692 char *args = (char *)calloc(len, sizeof(char));
1693 if (!args) {
1694 return -1;
1696 char *pargs = args; // extra pointer to after the last argument
1697 // build argument list in the format the DosStartSession() wants,
1698 // adding spaces between the arguments
1699 for (int i = 0; i < aArgc; i++, *pargs++ = ' ') {
1700 strcpy(pargs, aArgv[i]);
1701 pargs += strlen(aArgv[i]);
1703 if (aArgc > 1) {
1704 *(pargs-1) = '\0'; // replace last space
1706 *pargs = '\0';
1707 // make sure that the program is separated by null byte
1708 pargs = strchr(args, ' ');
1709 if (pargs) {
1710 *pargs = '\0';
1713 char *env = createEnv();
1715 char error[CCHMAXPATH] = { 0 };
1716 RESULTCODES crc = { 0 };
1717 ULONG rc = DosExecPgm(error, sizeof(error), EXEC_ASYNC, args, env,
1718 &crc, (PSZ)aExePath);
1719 free(args); // done with the arguments
1720 if (env) {
1721 free(env);
1723 if (rc != NO_ERROR) {
1724 return -1;
1727 return 0;
1729 #endif
1731 // If aBlankCommandLine is true, then the application will be launched with a
1732 // blank command line instead of being launched with the same command line that
1733 // it was initially started with.
1734 static nsresult LaunchChild(nsINativeAppSupport* aNative,
1735 PRBool aBlankCommandLine = PR_FALSE)
1737 aNative->Quit(); // release DDE mutex, if we're holding it
1739 // Restart this process by exec'ing it into the current process
1740 // if supported by the platform. Otherwise, use NSPR.
1742 if (aBlankCommandLine) {
1743 #if defined(MOZ_WIDGET_QT)
1744 // Remove only arguments not given to Qt
1745 gRestartArgc = gQtOnlyArgc;
1746 gRestartArgv = gQtOnlyArgv;
1747 #else
1748 gRestartArgc = 1;
1749 gRestartArgv[gRestartArgc] = nsnull;
1750 #endif
1753 SaveToEnv("MOZ_LAUNCHED_CHILD=1");
1755 #if defined(ANDROID)
1756 mozilla::AndroidBridge::Bridge()->ScheduleRestart();
1757 #else
1758 #if defined(XP_MACOSX)
1759 CommandLineServiceMac::SetupMacCommandLine(gRestartArgc, gRestartArgv, PR_TRUE);
1760 LaunchChildMac(gRestartArgc, gRestartArgv);
1761 #else
1762 nsCOMPtr<nsILocalFile> lf;
1763 nsresult rv = XRE_GetBinaryPath(gArgv[0], getter_AddRefs(lf));
1764 if (NS_FAILED(rv))
1765 return rv;
1767 #if defined(XP_WIN)
1768 nsAutoString exePath;
1769 rv = lf->GetPath(exePath);
1770 if (NS_FAILED(rv))
1771 return rv;
1773 if (!WinLaunchChild(exePath.get(), gRestartArgc, gRestartArgv))
1774 return NS_ERROR_FAILURE;
1776 #else
1777 nsCAutoString exePath;
1778 rv = lf->GetNativePath(exePath);
1779 if (NS_FAILED(rv))
1780 return rv;
1782 #if defined(XP_OS2) && (__KLIBC__ == 0 && __KLIBC_MINOR__ >= 6)
1783 // implementation of _execv() is broken with kLibc 0.6.x and later
1784 if (OS2LaunchChild(exePath.get(), gRestartArgc, gRestartArgv) == -1)
1785 return NS_ERROR_FAILURE;
1786 #elif defined(XP_OS2)
1787 if (_execv(exePath.get(), gRestartArgv) == -1)
1788 return NS_ERROR_FAILURE;
1789 #elif defined(XP_UNIX)
1790 if (execv(exePath.get(), gRestartArgv) == -1)
1791 return NS_ERROR_FAILURE;
1792 #elif defined(XP_BEOS)
1793 extern char **environ;
1794 status_t res;
1795 res = resume_thread(load_image(gRestartArgc,(const char **)gRestartArgv,(const char **)environ));
1796 if (res != B_OK)
1797 return NS_ERROR_FAILURE;
1798 #else
1799 PRProcess* process = PR_CreateProcess(exePath.get(), gRestartArgv,
1800 nsnull, nsnull);
1801 if (!process) return NS_ERROR_FAILURE;
1803 PRInt32 exitCode;
1804 PRStatus failed = PR_WaitProcess(process, &exitCode);
1805 if (failed || exitCode)
1806 return NS_ERROR_FAILURE;
1807 #endif // XP_OS2 series
1808 #endif // WP_WIN
1809 #endif // WP_MACOSX
1810 #endif // ANDROID
1812 return NS_ERROR_LAUNCHED_CHILD_PROCESS;
1815 static const char kProfileProperties[] =
1816 "chrome://mozapps/locale/profile/profileSelection.properties";
1818 static nsresult
1819 ProfileLockedDialog(nsILocalFile* aProfileDir, nsILocalFile* aProfileLocalDir,
1820 nsIProfileUnlocker* aUnlocker,
1821 nsINativeAppSupport* aNative, nsIProfileLock* *aResult)
1823 nsresult rv;
1825 ScopedXPCOMStartup xpcom;
1826 rv = xpcom.Initialize();
1827 NS_ENSURE_SUCCESS(rv, rv);
1829 rv = xpcom.SetWindowCreator(aNative);
1830 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
1832 { //extra scoping is needed so we release these components before xpcom shutdown
1833 nsCOMPtr<nsIStringBundleService> sbs =
1834 mozilla::services::GetStringBundleService();
1835 NS_ENSURE_TRUE(sbs, NS_ERROR_FAILURE);
1837 nsCOMPtr<nsIStringBundle> sb;
1838 sbs->CreateBundle(kProfileProperties, getter_AddRefs(sb));
1839 NS_ENSURE_TRUE_LOG(sbs, NS_ERROR_FAILURE);
1841 NS_ConvertUTF8toUTF16 appName(gAppData->name);
1842 const PRUnichar* params[] = {appName.get(), appName.get()};
1844 nsXPIDLString killMessage;
1845 #ifndef XP_MACOSX
1846 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"
1847 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"
1848 #else
1849 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"
1850 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"
1851 #endif
1853 sb->FormatStringFromName(aUnlocker ? kRestartUnlocker : kRestartNoUnlocker,
1854 params, 2, getter_Copies(killMessage));
1856 nsXPIDLString killTitle;
1857 sb->FormatStringFromName(NS_LITERAL_STRING("restartTitle").get(),
1858 params, 1, getter_Copies(killTitle));
1860 if (!killMessage || !killTitle)
1861 return NS_ERROR_FAILURE;
1863 nsCOMPtr<nsIPromptService> ps
1864 (do_GetService(NS_PROMPTSERVICE_CONTRACTID));
1865 NS_ENSURE_TRUE(ps, NS_ERROR_FAILURE);
1867 PRUint32 flags = nsIPromptService::BUTTON_TITLE_OK * nsIPromptService::BUTTON_POS_0;
1869 if (aUnlocker) {
1870 flags =
1871 nsIPromptService::BUTTON_TITLE_CANCEL * nsIPromptService::BUTTON_POS_0 +
1872 nsIPromptService::BUTTON_TITLE_IS_STRING * nsIPromptService::BUTTON_POS_1 +
1873 nsIPromptService::BUTTON_POS_1_DEFAULT;
1876 PRInt32 button;
1877 PRBool checkState;
1878 rv = ps->ConfirmEx(nsnull, killTitle, killMessage, flags,
1879 killTitle, nsnull, nsnull, nsnull, &checkState, &button);
1880 NS_ENSURE_SUCCESS_LOG(rv, rv);
1882 if (button == 1 && aUnlocker) {
1883 rv = aUnlocker->Unlock(nsIProfileUnlocker::FORCE_QUIT);
1884 if (NS_FAILED(rv)) return rv;
1886 return NS_LockProfilePath(aProfileDir, aProfileLocalDir, nsnull, aResult);
1889 return NS_ERROR_ABORT;
1893 static nsresult
1894 ProfileMissingDialog(nsINativeAppSupport* aNative)
1896 nsresult rv;
1898 ScopedXPCOMStartup xpcom;
1899 rv = xpcom.Initialize();
1900 NS_ENSURE_SUCCESS(rv, rv);
1902 rv = xpcom.SetWindowCreator(aNative);
1903 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
1905 { //extra scoping is needed so we release these components before xpcom shutdown
1906 nsCOMPtr<nsIStringBundleService> sbs =
1907 mozilla::services::GetStringBundleService();
1908 NS_ENSURE_TRUE(sbs, NS_ERROR_FAILURE);
1910 nsCOMPtr<nsIStringBundle> sb;
1911 sbs->CreateBundle(kProfileProperties, getter_AddRefs(sb));
1912 NS_ENSURE_TRUE_LOG(sbs, NS_ERROR_FAILURE);
1914 NS_ConvertUTF8toUTF16 appName(gAppData->name);
1915 const PRUnichar* params[] = {appName.get(), appName.get()};
1917 nsXPIDLString missingMessage;
1919 // profileMissing
1920 static const PRUnichar kMissing[] = {'p','r','o','f','i','l','e','M','i','s','s','i','n','g','\0'};
1921 sb->FormatStringFromName(kMissing, params, 2, getter_Copies(missingMessage));
1923 nsXPIDLString missingTitle;
1924 sb->FormatStringFromName(NS_LITERAL_STRING("profileMissingTitle").get(),
1925 params, 1, getter_Copies(missingTitle));
1927 if (missingMessage && missingTitle) {
1928 nsCOMPtr<nsIPromptService> ps
1929 (do_GetService(NS_PROMPTSERVICE_CONTRACTID));
1930 NS_ENSURE_TRUE(ps, NS_ERROR_FAILURE);
1932 ps->Alert(nsnull, missingTitle, missingMessage);
1935 return NS_ERROR_ABORT;
1939 static const char kProfileManagerURL[] =
1940 "chrome://mozapps/content/profile/profileSelection.xul";
1942 static nsresult
1943 ShowProfileManager(nsIToolkitProfileService* aProfileSvc,
1944 nsINativeAppSupport* aNative)
1946 nsresult rv;
1948 nsCOMPtr<nsILocalFile> profD, profLD;
1949 PRUnichar* profileNamePtr;
1950 nsCAutoString profileName;
1953 ScopedXPCOMStartup xpcom;
1954 rv = xpcom.Initialize();
1955 NS_ENSURE_SUCCESS(rv, rv);
1957 rv = xpcom.SetWindowCreator(aNative);
1958 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
1960 #ifdef XP_MACOSX
1961 CommandLineServiceMac::SetupMacCommandLine(gRestartArgc, gRestartArgv, PR_TRUE);
1962 #endif
1964 #ifdef XP_WIN
1965 // we don't have to wait here because profile manager window will pump
1966 // and DDE message will be handled
1967 ProcessDDE(aNative, PR_FALSE);
1968 #endif
1970 { //extra scoping is needed so we release these components before xpcom shutdown
1971 nsCOMPtr<nsIWindowWatcher> windowWatcher
1972 (do_GetService(NS_WINDOWWATCHER_CONTRACTID));
1973 nsCOMPtr<nsIDialogParamBlock> ioParamBlock
1974 (do_CreateInstance(NS_DIALOGPARAMBLOCK_CONTRACTID));
1975 nsCOMPtr<nsIMutableArray> dlgArray (do_CreateInstance(NS_ARRAY_CONTRACTID));
1976 NS_ENSURE_TRUE(windowWatcher && ioParamBlock && dlgArray, NS_ERROR_FAILURE);
1978 ioParamBlock->SetObjects(dlgArray);
1980 nsCOMPtr<nsIAppStartup> appStartup
1981 (do_GetService(NS_APPSTARTUP_CONTRACTID));
1982 NS_ENSURE_TRUE(appStartup, NS_ERROR_FAILURE);
1984 nsCOMPtr<nsIDOMWindow> newWindow;
1985 rv = windowWatcher->OpenWindow(nsnull,
1986 kProfileManagerURL,
1987 "_blank",
1988 "centerscreen,chrome,modal,titlebar",
1989 ioParamBlock,
1990 getter_AddRefs(newWindow));
1992 NS_ENSURE_SUCCESS_LOG(rv, rv);
1994 aProfileSvc->Flush();
1996 PRInt32 dialogConfirmed;
1997 rv = ioParamBlock->GetInt(0, &dialogConfirmed);
1998 if (NS_FAILED(rv) || dialogConfirmed == 0) return NS_ERROR_ABORT;
2000 nsCOMPtr<nsIProfileLock> lock;
2001 rv = dlgArray->QueryElementAt(0, NS_GET_IID(nsIProfileLock),
2002 getter_AddRefs(lock));
2003 NS_ENSURE_SUCCESS_LOG(rv, rv);
2005 rv = lock->GetDirectory(getter_AddRefs(profD));
2006 NS_ENSURE_SUCCESS(rv, rv);
2008 rv = lock->GetLocalDirectory(getter_AddRefs(profLD));
2009 NS_ENSURE_SUCCESS(rv, rv);
2011 rv = ioParamBlock->GetString(0, &profileNamePtr);
2012 NS_ENSURE_SUCCESS(rv, rv);
2014 CopyUTF16toUTF8(profileNamePtr, profileName);
2015 NS_Free(profileNamePtr);
2017 lock->Unlock();
2021 SaveFileToEnv("XRE_PROFILE_PATH", profD);
2022 SaveFileToEnv("XRE_PROFILE_LOCAL_PATH", profLD);
2023 SaveWordToEnv("XRE_PROFILE_NAME", profileName);
2025 PRBool offline = PR_FALSE;
2026 aProfileSvc->GetStartOffline(&offline);
2027 if (offline) {
2028 SaveToEnv("XRE_START_OFFLINE=1");
2031 return LaunchChild(aNative);
2034 static nsresult
2035 ImportProfiles(nsIToolkitProfileService* aPService,
2036 nsINativeAppSupport* aNative)
2038 nsresult rv;
2040 SaveToEnv("XRE_IMPORT_PROFILES=1");
2042 // try to import old-style profiles
2043 { // scope XPCOM
2044 ScopedXPCOMStartup xpcom;
2045 rv = xpcom.Initialize();
2046 if (NS_SUCCEEDED(rv)) {
2047 #ifdef XP_MACOSX
2048 CommandLineServiceMac::SetupMacCommandLine(gRestartArgc, gRestartArgv, PR_TRUE);
2049 #endif
2051 nsCOMPtr<nsIProfileMigrator> migrator
2052 (do_GetService(NS_PROFILEMIGRATOR_CONTRACTID));
2053 if (migrator) {
2054 migrator->Import();
2059 aPService->Flush();
2060 return LaunchChild(aNative);
2063 // Pick a profile. We need to end up with a profile lock.
2065 // 1) check for -profile <path>
2066 // 2) check for -P <name>
2067 // 3) check for -ProfileManager
2068 // 4) use the default profile, if there is one
2069 // 5) if there are *no* profiles, set up profile-migration
2070 // 6) display the profile-manager UI
2072 static PRBool gDoMigration = PR_FALSE;
2074 static nsresult
2075 SelectProfile(nsIProfileLock* *aResult, nsINativeAppSupport* aNative,
2076 PRBool* aStartOffline, nsACString* aProfileName)
2078 nsresult rv;
2079 ArgResult ar;
2080 const char* arg;
2081 *aResult = nsnull;
2082 *aStartOffline = PR_FALSE;
2084 ar = CheckArg("offline", PR_TRUE);
2085 if (ar == ARG_BAD) {
2086 PR_fprintf(PR_STDERR, "Error: argument -offline is invalid when argument -osint is specified\n");
2087 return NS_ERROR_FAILURE;
2090 arg = PR_GetEnv("XRE_START_OFFLINE");
2091 if ((arg && *arg) || ar)
2092 *aStartOffline = PR_TRUE;
2095 nsCOMPtr<nsILocalFile> lf = GetFileFromEnv("XRE_PROFILE_PATH");
2096 if (lf) {
2097 nsCOMPtr<nsILocalFile> localDir =
2098 GetFileFromEnv("XRE_PROFILE_LOCAL_PATH");
2099 if (!localDir) {
2100 localDir = lf;
2103 arg = PR_GetEnv("XRE_PROFILE_NAME");
2104 if (arg && *arg && aProfileName)
2105 aProfileName->Assign(nsDependentCString(arg));
2107 // Clear out flags that we handled (or should have handled!) last startup.
2108 const char *dummy;
2109 CheckArg("p", PR_FALSE, &dummy);
2110 CheckArg("profile", PR_FALSE, &dummy);
2111 CheckArg("profilemanager");
2113 return NS_LockProfilePath(lf, localDir, nsnull, aResult);
2116 ar = CheckArg("migration", PR_TRUE);
2117 if (ar == ARG_BAD) {
2118 PR_fprintf(PR_STDERR, "Error: argument -migration is invalid when argument -osint is specified\n");
2119 return NS_ERROR_FAILURE;
2120 } else if (ar == ARG_FOUND) {
2121 gDoMigration = PR_TRUE;
2124 ar = CheckArg("profile", PR_TRUE, &arg);
2125 if (ar == ARG_BAD) {
2126 PR_fprintf(PR_STDERR, "Error: argument -profile requires a path\n");
2127 return NS_ERROR_FAILURE;
2129 if (ar) {
2130 nsCOMPtr<nsILocalFile> lf;
2131 rv = XRE_GetFileFromPath(arg, getter_AddRefs(lf));
2132 NS_ENSURE_SUCCESS(rv, rv);
2134 nsCOMPtr<nsIProfileUnlocker> unlocker;
2136 // Check if the profile path exists and it's a directory.
2137 PRBool exists;
2138 lf->Exists(&exists);
2139 if (!exists) {
2140 rv = lf->Create(nsIFile::DIRECTORY_TYPE, 0700);
2141 NS_ENSURE_SUCCESS(rv, rv);
2144 // If a profile path is specified directory on the command line, then
2145 // assume that the temp directory is the same as the given directory.
2146 rv = NS_LockProfilePath(lf, lf, getter_AddRefs(unlocker), aResult);
2147 if (NS_SUCCEEDED(rv))
2148 return rv;
2150 return ProfileLockedDialog(lf, lf, unlocker, aNative, aResult);
2153 nsCOMPtr<nsIToolkitProfileService> profileSvc;
2154 rv = NS_NewToolkitProfileService(getter_AddRefs(profileSvc));
2155 if (rv == NS_ERROR_FILE_ACCESS_DENIED)
2156 PR_fprintf(PR_STDERR, "Error: Access was denied while trying to open files in " \
2157 "your profile directory.\n");
2158 NS_ENSURE_SUCCESS(rv, rv);
2160 ar = CheckArg("createprofile", PR_TRUE, &arg);
2161 if (ar == ARG_BAD) {
2162 PR_fprintf(PR_STDERR, "Error: argument -createprofile requires a profile name\n");
2163 return NS_ERROR_FAILURE;
2165 if (ar) {
2166 nsCOMPtr<nsIToolkitProfile> profile;
2168 const char* delim = strchr(arg, ' ');
2169 if (delim) {
2170 nsCOMPtr<nsILocalFile> lf;
2171 rv = NS_NewNativeLocalFile(nsDependentCString(delim + 1),
2172 PR_TRUE, getter_AddRefs(lf));
2173 if (NS_FAILED(rv)) {
2174 PR_fprintf(PR_STDERR, "Error: profile path not valid.\n");
2175 return rv;
2178 // As with -profile, assume that the given path will be used for both the
2179 // main profile directory and the temp profile directory.
2180 rv = profileSvc->CreateProfile(lf, lf, nsDependentCSubstring(arg, delim),
2181 getter_AddRefs(profile));
2182 } else {
2183 rv = profileSvc->CreateProfile(nsnull, nsnull, nsDependentCString(arg),
2184 getter_AddRefs(profile));
2186 // Some pathological arguments can make it this far
2187 if (NS_FAILED(rv)) {
2188 PR_fprintf(PR_STDERR, "Error creating profile.\n");
2189 return rv;
2191 rv = NS_ERROR_ABORT;
2192 profileSvc->Flush();
2194 // XXXben need to ensure prefs.js exists here so the tinderboxes will
2195 // not go orange.
2196 nsCOMPtr<nsILocalFile> prefsJSFile;
2197 profile->GetRootDir(getter_AddRefs(prefsJSFile));
2198 prefsJSFile->AppendNative(NS_LITERAL_CSTRING("prefs.js"));
2199 nsCAutoString pathStr;
2200 prefsJSFile->GetNativePath(pathStr);
2201 PR_fprintf(PR_STDERR, "Success: created profile '%s' at '%s'\n", arg, pathStr.get());
2202 PRBool exists;
2203 prefsJSFile->Exists(&exists);
2204 if (!exists)
2205 prefsJSFile->Create(nsIFile::NORMAL_FILE_TYPE, 0644);
2206 // XXXdarin perhaps 0600 would be better?
2208 return rv;
2211 PRUint32 count;
2212 rv = profileSvc->GetProfileCount(&count);
2213 NS_ENSURE_SUCCESS(rv, rv);
2215 if (gAppData->flags & NS_XRE_ENABLE_PROFILE_MIGRATOR) {
2216 arg = PR_GetEnv("XRE_IMPORT_PROFILES");
2217 if (!count && (!arg || !*arg)) {
2218 return ImportProfiles(profileSvc, aNative);
2222 ar = CheckArg("p", PR_FALSE, &arg);
2223 if (ar == ARG_BAD) {
2224 ar = CheckArg("osint");
2225 if (ar == ARG_FOUND) {
2226 PR_fprintf(PR_STDERR, "Error: argument -p is invalid when argument -osint is specified\n");
2227 return NS_ERROR_FAILURE;
2229 return ShowProfileManager(profileSvc, aNative);
2231 if (ar) {
2232 ar = CheckArg("osint");
2233 if (ar == ARG_FOUND) {
2234 PR_fprintf(PR_STDERR, "Error: argument -p is invalid when argument -osint is specified\n");
2235 return NS_ERROR_FAILURE;
2237 nsCOMPtr<nsIToolkitProfile> profile;
2238 rv = profileSvc->GetProfileByName(nsDependentCString(arg),
2239 getter_AddRefs(profile));
2240 if (NS_SUCCEEDED(rv)) {
2241 nsCOMPtr<nsIProfileUnlocker> unlocker;
2242 rv = profile->Lock(nsnull, aResult);
2243 if (NS_SUCCEEDED(rv)) {
2244 if (aProfileName)
2245 aProfileName->Assign(nsDependentCString(arg));
2246 return NS_OK;
2249 nsCOMPtr<nsILocalFile> profileDir;
2250 rv = profile->GetRootDir(getter_AddRefs(profileDir));
2251 NS_ENSURE_SUCCESS(rv, rv);
2253 nsCOMPtr<nsILocalFile> profileLocalDir;
2254 rv = profile->GetLocalDir(getter_AddRefs(profileLocalDir));
2255 NS_ENSURE_SUCCESS(rv, rv);
2257 return ProfileLockedDialog(profileDir, profileLocalDir, unlocker,
2258 aNative, aResult);
2261 return ShowProfileManager(profileSvc, aNative);
2264 ar = CheckArg("profilemanager", PR_TRUE);
2265 if (ar == ARG_BAD) {
2266 PR_fprintf(PR_STDERR, "Error: argument -profilemanager is invalid when argument -osint is specified\n");
2267 return NS_ERROR_FAILURE;
2268 } else if (ar == ARG_FOUND) {
2269 return ShowProfileManager(profileSvc, aNative);
2272 if (!count) {
2273 gDoMigration = PR_TRUE;
2275 // create a default profile
2276 nsCOMPtr<nsIToolkitProfile> profile;
2277 nsresult rv = profileSvc->CreateProfile(nsnull, // choose a default dir for us
2278 nsnull, // choose a default dir for us
2279 NS_LITERAL_CSTRING("default"),
2280 getter_AddRefs(profile));
2281 if (NS_SUCCEEDED(rv)) {
2282 profileSvc->Flush();
2283 rv = profile->Lock(nsnull, aResult);
2284 if (NS_SUCCEEDED(rv)) {
2285 if (aProfileName)
2286 aProfileName->Assign(NS_LITERAL_CSTRING("default"));
2287 return NS_OK;
2292 PRBool useDefault = PR_TRUE;
2293 if (count > 1)
2294 profileSvc->GetStartWithLastProfile(&useDefault);
2296 if (useDefault) {
2297 nsCOMPtr<nsIToolkitProfile> profile;
2298 // GetSelectedProfile will auto-select the only profile if there's just one
2299 profileSvc->GetSelectedProfile(getter_AddRefs(profile));
2300 if (profile) {
2301 nsCOMPtr<nsIProfileUnlocker> unlocker;
2302 rv = profile->Lock(getter_AddRefs(unlocker), aResult);
2303 if (NS_SUCCEEDED(rv)) {
2304 // Try to grab the profile name.
2305 if (aProfileName) {
2306 rv = profile->GetName(*aProfileName);
2307 if (NS_FAILED(rv))
2308 aProfileName->Truncate(0);
2310 return NS_OK;
2313 nsCOMPtr<nsILocalFile> profileDir;
2314 rv = profile->GetRootDir(getter_AddRefs(profileDir));
2315 NS_ENSURE_SUCCESS(rv, rv);
2317 nsCOMPtr<nsILocalFile> profileLocalDir;
2318 rv = profile->GetRootDir(getter_AddRefs(profileLocalDir));
2319 NS_ENSURE_SUCCESS(rv, rv);
2321 return ProfileLockedDialog(profileDir, profileLocalDir, unlocker,
2322 aNative, aResult);
2326 return ShowProfileManager(profileSvc, aNative);
2329 /**
2330 * Checks the compatibility.ini file to see if we have updated our application
2331 * or otherwise invalidated our caches. If the application has been updated,
2332 * we return PR_FALSE; otherwise, we return PR_TRUE. We also write the status
2333 * of the caches (valid/invalid) into the return param aCachesOK. The aCachesOK
2334 * is always invalid if the application has been updated.
2336 static PRBool
2337 CheckCompatibility(nsIFile* aProfileDir, const nsCString& aVersion,
2338 const nsCString& aOSABI, nsIFile* aXULRunnerDir,
2339 nsIFile* aAppDir, nsILocalFile* aFlagFile,
2340 PRBool* aCachesOK)
2342 *aCachesOK = PR_FALSE;
2343 nsCOMPtr<nsIFile> file;
2344 aProfileDir->Clone(getter_AddRefs(file));
2345 if (!file)
2346 return PR_FALSE;
2347 file->AppendNative(FILE_COMPATIBILITY_INFO);
2349 nsINIParser parser;
2350 nsCOMPtr<nsILocalFile> localFile(do_QueryInterface(file));
2351 nsresult rv = parser.Init(localFile);
2352 if (NS_FAILED(rv))
2353 return PR_FALSE;
2355 nsCAutoString buf;
2356 rv = parser.GetString("Compatibility", "LastVersion", buf);
2357 if (NS_FAILED(rv) || !aVersion.Equals(buf))
2358 return PR_FALSE;
2360 rv = parser.GetString("Compatibility", "LastOSABI", buf);
2361 if (NS_FAILED(rv) || !aOSABI.Equals(buf))
2362 return PR_FALSE;
2364 rv = parser.GetString("Compatibility", "LastPlatformDir", buf);
2365 if (NS_FAILED(rv))
2366 return PR_FALSE;
2368 nsCOMPtr<nsILocalFile> lf;
2369 rv = NS_NewNativeLocalFile(buf, PR_FALSE,
2370 getter_AddRefs(lf));
2371 if (NS_FAILED(rv))
2372 return PR_FALSE;
2374 PRBool eq;
2375 rv = lf->Equals(aXULRunnerDir, &eq);
2376 if (NS_FAILED(rv) || !eq)
2377 return PR_FALSE;
2379 if (aAppDir) {
2380 rv = parser.GetString("Compatibility", "LastAppDir", buf);
2381 if (NS_FAILED(rv))
2382 return PR_FALSE;
2384 rv = NS_NewNativeLocalFile(buf, PR_FALSE,
2385 getter_AddRefs(lf));
2386 if (NS_FAILED(rv))
2387 return PR_FALSE;
2389 rv = lf->Equals(aAppDir, &eq);
2390 if (NS_FAILED(rv) || !eq)
2391 return PR_FALSE;
2394 // If we see this flag, caches are invalid.
2395 rv = parser.GetString("Compatibility", "InvalidateCaches", buf);
2396 *aCachesOK = (NS_FAILED(rv) || !buf.EqualsLiteral("1"));
2398 #ifdef DEBUG
2399 PRBool purgeCaches = PR_FALSE;
2400 if (aFlagFile) {
2401 aFlagFile->Exists(&purgeCaches);
2404 *aCachesOK = !purgeCaches && *aCachesOK;
2405 #endif
2406 return PR_TRUE;
2409 static void BuildVersion(nsCString &aBuf)
2411 aBuf.Assign(gAppData->version);
2412 aBuf.Append('_');
2413 aBuf.Append(gAppData->buildID);
2414 aBuf.Append('/');
2415 aBuf.Append(gToolkitBuildID);
2418 static void
2419 WriteVersion(nsIFile* aProfileDir, const nsCString& aVersion,
2420 const nsCString& aOSABI, nsIFile* aXULRunnerDir,
2421 nsIFile* aAppDir)
2423 nsCOMPtr<nsIFile> file;
2424 aProfileDir->Clone(getter_AddRefs(file));
2425 if (!file)
2426 return;
2427 file->AppendNative(FILE_COMPATIBILITY_INFO);
2429 nsCOMPtr<nsILocalFile> lf = do_QueryInterface(file);
2431 nsCAutoString platformDir;
2432 aXULRunnerDir->GetNativePath(platformDir);
2434 nsCAutoString appDir;
2435 if (aAppDir)
2436 aAppDir->GetNativePath(appDir);
2438 PRFileDesc *fd = nsnull;
2439 lf->OpenNSPRFileDesc(PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, 0600, &fd);
2440 if (!fd) {
2441 NS_ERROR("could not create output stream");
2442 return;
2445 static const char kHeader[] = "[Compatibility]" NS_LINEBREAK
2446 "LastVersion=";
2448 PR_Write(fd, kHeader, sizeof(kHeader) - 1);
2449 PR_Write(fd, aVersion.get(), aVersion.Length());
2451 static const char kOSABIHeader[] = NS_LINEBREAK "LastOSABI=";
2452 PR_Write(fd, kOSABIHeader, sizeof(kOSABIHeader) - 1);
2453 PR_Write(fd, aOSABI.get(), aOSABI.Length());
2455 static const char kPlatformDirHeader[] = NS_LINEBREAK "LastPlatformDir=";
2457 PR_Write(fd, kPlatformDirHeader, sizeof(kPlatformDirHeader) - 1);
2458 PR_Write(fd, platformDir.get(), platformDir.Length());
2460 static const char kAppDirHeader[] = NS_LINEBREAK "LastAppDir=";
2461 if (aAppDir) {
2462 PR_Write(fd, kAppDirHeader, sizeof(kAppDirHeader) - 1);
2463 PR_Write(fd, appDir.get(), appDir.Length());
2466 static const char kNL[] = NS_LINEBREAK;
2467 PR_Write(fd, kNL, sizeof(kNL) - 1);
2469 PR_Close(fd);
2472 static void RemoveComponentRegistries(nsIFile* aProfileDir, nsIFile* aLocalProfileDir,
2473 PRBool aRemoveEMFiles)
2475 nsCOMPtr<nsIFile> file;
2476 aProfileDir->Clone(getter_AddRefs(file));
2477 if (!file)
2478 return;
2480 if (aRemoveEMFiles) {
2481 file->SetNativeLeafName(NS_LITERAL_CSTRING("extensions.ini"));
2482 file->Remove(PR_FALSE);
2485 aLocalProfileDir->Clone(getter_AddRefs(file));
2486 if (!file)
2487 return;
2489 file->AppendNative(NS_LITERAL_CSTRING("XUL" PLATFORM_FASL_SUFFIX));
2490 file->Remove(PR_FALSE);
2492 file->SetNativeLeafName(NS_LITERAL_CSTRING("XPC" PLATFORM_FASL_SUFFIX));
2493 file->Remove(PR_FALSE);
2495 file->SetNativeLeafName(NS_LITERAL_CSTRING("startupCache"));
2496 file->Remove(PR_TRUE);
2499 // To support application initiated restart via nsIAppStartup.quit, we
2500 // need to save various environment variables, and then restore them
2501 // before re-launching the application.
2503 static struct {
2504 const char *name;
2505 char *value;
2506 } gSavedVars[] = {
2507 {"XUL_APP_FILE", nsnull}
2510 static void SaveStateForAppInitiatedRestart()
2512 for (size_t i = 0; i < NS_ARRAY_LENGTH(gSavedVars); ++i) {
2513 const char *s = PR_GetEnv(gSavedVars[i].name);
2514 if (s)
2515 gSavedVars[i].value = PR_smprintf("%s=%s", gSavedVars[i].name, s);
2519 static void RestoreStateForAppInitiatedRestart()
2521 for (size_t i = 0; i < NS_ARRAY_LENGTH(gSavedVars); ++i) {
2522 if (gSavedVars[i].value)
2523 PR_SetEnv(gSavedVars[i].value);
2527 #ifdef MOZ_CRASHREPORTER
2528 // When we first initialize the crash reporter we don't have a profile,
2529 // so we set the minidump path to $TEMP. Once we have a profile,
2530 // we set it to $PROFILE/minidumps, creating the directory
2531 // if needed.
2532 static void MakeOrSetMinidumpPath(nsIFile* profD)
2534 nsCOMPtr<nsIFile> dumpD;
2535 nsresult rv = profD->Clone(getter_AddRefs(dumpD));
2537 if(dumpD) {
2538 PRBool fileExists;
2539 //XXX: do some more error checking here
2540 dumpD->Append(NS_LITERAL_STRING("minidumps"));
2541 rv = dumpD->Exists(&fileExists);
2542 if(!fileExists) {
2543 dumpD->Create(nsIFile::DIRECTORY_TYPE, 0700);
2546 nsAutoString pathStr;
2547 if(NS_SUCCEEDED(dumpD->GetPath(pathStr)))
2548 CrashReporter::SetMinidumpPath(pathStr);
2551 #endif
2553 const nsXREAppData* gAppData = nsnull;
2555 #if defined(XP_OS2)
2556 // because we use early returns, we use a stack-based helper to un-set the OS2 FP handler
2557 class ScopedFPHandler {
2558 private:
2559 EXCEPTIONREGISTRATIONRECORD excpreg;
2561 public:
2562 ScopedFPHandler() { PR_OS2_SetFloatExcpHandler(&excpreg); }
2563 ~ScopedFPHandler() { PR_OS2_UnsetFloatExcpHandler(&excpreg); }
2565 #endif
2567 #ifdef MOZ_WIDGET_GTK2
2568 #include "prlink.h"
2569 typedef void (*_g_set_application_name_fn)(const gchar *application_name);
2570 typedef void (*_gtk_window_set_auto_startup_notification_fn)(gboolean setting);
2572 static PRFuncPtr FindFunction(const char* aName)
2574 PRLibrary *lib = nsnull;
2575 PRFuncPtr result = PR_FindFunctionSymbolAndLibrary(aName, &lib);
2576 // Since the library was already loaded, we can safely unload it here.
2577 if (lib) {
2578 PR_UnloadLibrary(lib);
2580 return result;
2583 static nsIWidget* GetMainWidget(nsIDOMWindow* aWindow)
2585 // get the native window for this instance
2586 nsCOMPtr<nsPIDOMWindow> window(do_QueryInterface(aWindow));
2587 NS_ENSURE_TRUE(window, nsnull);
2589 nsCOMPtr<nsIBaseWindow> baseWindow
2590 (do_QueryInterface(window->GetDocShell()));
2591 NS_ENSURE_TRUE(baseWindow, nsnull);
2593 nsCOMPtr<nsIWidget> mainWidget;
2594 baseWindow->GetMainWidget(getter_AddRefs(mainWidget));
2595 return mainWidget;
2598 static nsGTKToolkit* GetGTKToolkit()
2600 nsCOMPtr<nsIAppShellService> svc = do_GetService(NS_APPSHELLSERVICE_CONTRACTID);
2601 if (!svc)
2602 return nsnull;
2603 nsCOMPtr<nsIDOMWindowInternal> window;
2604 svc->GetHiddenDOMWindow(getter_AddRefs(window));
2605 if (!window)
2606 return nsnull;
2607 nsIWidget* widget = GetMainWidget(window);
2608 if (!widget)
2609 return nsnull;
2610 nsIToolkit* toolkit = widget->GetToolkit();
2611 if (!toolkit)
2612 return nsnull;
2613 return static_cast<nsGTKToolkit*>(toolkit);
2616 static void MOZ_gdk_display_close(GdkDisplay *display)
2618 // XXX wallpaper for bug 417163: don't close the Display if we're using the
2619 // Qt theme because we crash (in Qt code) when using jemalloc.
2620 PRBool theme_is_qt = PR_FALSE;
2621 GtkSettings* settings =
2622 gtk_settings_get_for_screen(gdk_display_get_default_screen(display));
2623 gchar *theme_name;
2624 g_object_get(settings, "gtk-theme-name", &theme_name, NULL);
2625 if (theme_name) {
2626 theme_is_qt = strcmp(theme_name, "Qt") == 0;
2627 if (theme_is_qt)
2628 NS_WARNING("wallpaper bug 417163 for Qt theme");
2629 g_free(theme_name);
2632 // gdk_display_close was broken prior to gtk+-2.10.0.
2633 // (http://bugzilla.gnome.org/show_bug.cgi?id=85715)
2634 // gdk_display_manager_set_default_display (gdk_display_manager_get(), NULL)
2635 // was also broken.
2636 if (gtk_check_version(2,10,0) != NULL) {
2637 #ifdef MOZ_X11
2638 // Version check failed - broken gdk_display_close.
2640 // Let the gdk structures leak but at least close the Display,
2641 // assuming that gdk will not use it again.
2642 Display* dpy = GDK_DISPLAY_XDISPLAY(display);
2643 if (!theme_is_qt)
2644 XCloseDisplay(dpy);
2645 #else
2646 gdk_display_close(display);
2647 #endif /* MOZ_X11 */
2649 else {
2650 #if CLEANUP_MEMORY
2651 // Get a (new) Pango context that holds a reference to the fontmap that
2652 // GTK has been using. gdk_pango_context_get() must be called while GTK
2653 // has a default display.
2654 PangoContext *pangoContext = gdk_pango_context_get();
2655 #endif
2657 PRBool buggyCairoShutdown = cairo_version() < CAIRO_VERSION_ENCODE(1, 4, 0);
2659 if (!buggyCairoShutdown) {
2660 // We should shut down GDK before we shut down libraries it depends on
2661 // like Pango and cairo. But if cairo shutdown is buggy, we should
2662 // shut down cairo first otherwise it may crash because of dangling
2663 // references to Display objects (see bug 469831).
2664 if (!theme_is_qt)
2665 gdk_display_close(display);
2668 #if CLEANUP_MEMORY
2669 // This doesn't take a reference.
2670 PangoFontMap *fontmap = pango_context_get_font_map(pangoContext);
2671 // Do some shutdown of the fontmap, which releases the fonts, clearing a
2672 // bunch of circular references from the fontmap through the fonts back to
2673 // itself. The shutdown that this does is much less than what's done by
2674 // the fontmap's finalize, though.
2675 if (PANGO_IS_FC_FONT_MAP(fontmap))
2676 pango_fc_font_map_shutdown(PANGO_FC_FONT_MAP(fontmap));
2677 g_object_unref(pangoContext);
2678 // PangoCairo still holds a reference to the fontmap.
2679 // Now that we have finished with GTK and Pango, we could unref fontmap,
2680 // which would allow us to call FcFini, but removing what is really
2681 // Pango's ref feels a bit evil. Pango-1.22 will have support for
2682 // pango_cairo_font_map_set_default(NULL), which would release the
2683 // reference on the old fontmap.
2685 #if GTK_CHECK_VERSION(2,8,0)
2686 // cairo_debug_reset_static_data() is prototyped through cairo.h included
2687 // by gtk.h.
2688 #ifdef cairo_debug_reset_static_data
2689 #error "Looks like we're including Mozilla's cairo instead of system cairo"
2690 #endif
2691 cairo_debug_reset_static_data();
2692 #endif // 2.8.0
2693 #endif // CLEANUP_MEMORY
2695 if (buggyCairoShutdown) {
2696 if (!theme_is_qt)
2697 gdk_display_close(display);
2701 #endif // MOZ_WIDGET_GTK2
2703 /**
2704 * NSPR will search for the "nspr_use_zone_allocator" symbol throughout
2705 * the process and use it to determine whether the application defines its own
2706 * memory allocator or not.
2708 * Since most applications (e.g. Firefox and Thunderbird) don't use any special
2709 * allocators and therefore don't define this symbol, NSPR must search the
2710 * entire process, which reduces startup performance.
2712 * By defining the symbol here, we can avoid the wasted lookup and hopefully
2713 * improve startup performance.
2715 NS_VISIBILITY_DEFAULT PRBool nspr_use_zone_allocator = PR_FALSE;
2717 #ifdef MOZ_SPLASHSCREEN
2718 #define MOZ_SPLASHSCREEN_UPDATE(_i) do { if (splashScreen) splashScreen->Update(_i); } while(0)
2719 #else
2720 #define MOZ_SPLASHSCREEN_UPDATE(_i) do { } while(0)
2721 #endif
2723 #ifdef XP_WIN
2724 typedef BOOL (WINAPI* SetProcessDEPPolicyFunc)(DWORD dwFlags);
2725 #endif
2728 XRE_main(int argc, char* argv[], const nsXREAppData* aAppData)
2730 NS_TIME_FUNCTION;
2732 #ifdef MOZ_SPLASHSCREEN
2733 nsSplashScreen *splashScreen = nsnull;
2734 #endif
2736 nsresult rv;
2737 ArgResult ar;
2738 NS_TIMELINE_MARK("enter main");
2740 #ifdef DEBUG
2741 if (PR_GetEnv("XRE_MAIN_BREAK"))
2742 NS_BREAK();
2743 #endif
2745 SetupErrorHandling(argv[0]);
2747 #ifdef XP_UNIX
2748 const char *home = PR_GetEnv("HOME");
2749 if (!home || !*home) {
2750 struct passwd *pw = getpwuid(geteuid());
2751 if (!pw || !pw->pw_dir) {
2752 Output(PR_TRUE, "Could not determine HOME directory");
2753 return 1;
2755 SaveWordToEnv("HOME", nsDependentCString(pw->pw_dir));
2757 #endif
2759 #ifdef MOZ_ACCESSIBILITY_ATK
2760 // Reset GTK_MODULES, strip atk-bridge if exists
2761 // Mozilla will load libatk-bridge.so later if necessary
2762 const char* gtkModules = PR_GetEnv("GTK_MODULES");
2763 if (gtkModules && *gtkModules) {
2764 nsCString gtkModulesStr(gtkModules);
2765 gtkModulesStr.ReplaceSubstring("atk-bridge", "");
2766 char* expr = PR_smprintf("GTK_MODULES=%s", gtkModulesStr.get());
2767 if (expr)
2768 PR_SetEnv(expr);
2769 // We intentionally leak |expr| here since it is required by PR_SetEnv.
2772 // Suppress atk-bridge init at startup, it works after GNOME 2.24.2
2773 PR_SetEnv("NO_AT_BRIDGE=1");
2774 #endif
2776 gArgc = argc;
2777 gArgv = argv;
2779 NS_ENSURE_TRUE(aAppData, 2);
2781 #ifdef XP_MACOSX
2782 // The xulrunner stub executable tricks CFBundleGetMainBundle on
2783 // purpose into lying about the main bundle path. It will set
2784 // XRE_BINARY_PATH to inform us of our real location.
2785 gBinaryPath = getenv("XRE_BINARY_PATH");
2787 if (gBinaryPath && !*gBinaryPath)
2788 gBinaryPath = nsnull;
2789 #endif
2791 // Check for application.ini overrides
2792 const char* override = nsnull;
2793 ar = CheckArg("override", PR_TRUE, &override);
2794 if (ar == ARG_BAD) {
2795 Output(PR_TRUE, "Incorrect number of arguments passed to -override");
2796 return 1;
2798 else if (ar == ARG_FOUND) {
2799 nsCOMPtr<nsILocalFile> overrideLF;
2800 rv = XRE_GetFileFromPath(override, getter_AddRefs(overrideLF));
2801 if (NS_FAILED(rv)) {
2802 Output(PR_TRUE, "Error: unrecognized override.ini path.\n");
2803 return 1;
2806 nsXREAppData* overrideAppData = const_cast<nsXREAppData*>(aAppData);
2807 rv = XRE_ParseAppData(overrideLF, overrideAppData);
2808 if (NS_FAILED(rv)) {
2809 Output(PR_TRUE, "Couldn't read override.ini");
2810 return 1;
2814 ScopedAppData appData(aAppData);
2815 gAppData = &appData;
2817 // Check sanity and correctness of app data.
2819 if (!appData.name) {
2820 Output(PR_TRUE, "Error: App:Name not specified in application.ini\n");
2821 return 1;
2823 if (!appData.buildID) {
2824 Output(PR_TRUE, "Error: App:BuildID not specified in application.ini\n");
2825 return 1;
2828 #ifdef MOZ_SPLASHSCREEN
2829 // check to see if we need to do a splash screen
2830 PRBool wantsSplash = PR_TRUE;
2831 PRBool isNoSplash = (CheckArg("nosplash", PR_FALSE, NULL, PR_FALSE) == ARG_FOUND);
2832 isNoSplash |= (PR_GetEnv("NO_SPLASH") != 0);
2833 PRBool isNoRemote = (CheckArg("no-remote", PR_FALSE, NULL, PR_FALSE) == ARG_FOUND);
2835 #ifdef WINCE
2836 // synchronize startup; if it looks like we're going to have to
2837 // wait, then open up a splash screen
2838 WindowsMutex winStartupMutex(L"FirefoxStartupMutex");
2840 // try to lock the mutex, but only wait 100ms to do so
2841 PRBool needsMutexLock = ! winStartupMutex.Lock(100);
2843 // If we failed to lock the mutex quickly, then we'll want
2844 // a splash screen for sure.
2846 // If we did manage to lock it, then we'll only want one
2847 // a splash screen if there is no existing message window;
2848 // that is, if we are the first instance of the app.
2849 if (!needsMutexLock && !isNoRemote) {
2850 // check to see if there's a remote firefox up
2851 static PRUnichar classNameBuffer[128];
2852 _snwprintf(classNameBuffer, sizeof(classNameBuffer) / sizeof(PRUnichar),
2853 L"%S%s",
2854 gAppData->name, L"MessageWindow");
2855 HANDLE h = FindWindowW(classNameBuffer, 0);
2856 if (h) {
2857 // Someone else has the window, and we were able to grab the mutex,
2858 // meaning the other instance ahs presumably already finished starting
2859 // up by now. So no need for a splash screen.
2860 wantsSplash = PR_FALSE;
2861 CloseHandle(h);
2862 } else {
2863 // We couldn't find another window, and we were able to lock the mutex;
2864 // we're likely the first instance starting up, so make sure a splash
2865 // screen gets thrown up.
2866 wantsSplash = PR_TRUE;
2869 #endif //WINCE
2871 if (wantsSplash && !isNoSplash)
2872 splashScreen = nsSplashScreen::GetOrCreate();
2874 if (splashScreen)
2875 splashScreen->Open();
2877 #ifdef WINCE
2878 // Now that the splash screen is open, wait indefinitely
2879 // for the startup mutex on this thread if we need to.
2880 if (needsMutexLock)
2881 winStartupMutex.Lock();
2882 #endif //WINCE
2884 #endif //MOZ_SPLASHSCREEN
2887 ScopedLogging log;
2889 if (!appData.xreDirectory) {
2890 nsCOMPtr<nsILocalFile> lf;
2891 rv = XRE_GetBinaryPath(gArgv[0], getter_AddRefs(lf));
2892 if (NS_FAILED(rv))
2893 return 2;
2895 nsCOMPtr<nsIFile> greDir;
2896 rv = lf->GetParent(getter_AddRefs(greDir));
2897 if (NS_FAILED(rv))
2898 return 2;
2900 rv = CallQueryInterface(greDir, &appData.xreDirectory);
2901 if (NS_FAILED(rv))
2902 return 2;
2905 if (appData.size > offsetof(nsXREAppData, minVersion)) {
2906 if (!appData.minVersion) {
2907 Output(PR_TRUE, "Error: Gecko:MinVersion not specified in application.ini\n");
2908 return 1;
2911 if (!appData.maxVersion) {
2912 // If no maxVersion is specified, we assume the app is only compatible
2913 // with the initial preview release. Do not increment this number ever!
2914 SetAllocatedString(appData.maxVersion, "1.*");
2917 if (NS_CompareVersions(appData.minVersion, gToolkitVersion) > 0 ||
2918 NS_CompareVersions(appData.maxVersion, gToolkitVersion) < 0) {
2919 Output(PR_TRUE, "Error: Platform version '%s' is not compatible with\n"
2920 "minVersion >= %s\nmaxVersion <= %s\n",
2921 gToolkitVersion,
2922 appData.minVersion, appData.maxVersion);
2923 return 1;
2927 nsXREDirProvider dirProvider;
2928 rv = dirProvider.Initialize(gAppData->directory, gAppData->xreDirectory);
2929 if (NS_FAILED(rv))
2930 return 1;
2932 #ifdef MOZ_CRASHREPORTER
2933 const char* crashreporterEnv = PR_GetEnv("MOZ_CRASHREPORTER");
2934 if (crashreporterEnv && *crashreporterEnv) {
2935 appData.flags |= NS_XRE_ENABLE_CRASH_REPORTER;
2938 if ((appData.flags & NS_XRE_ENABLE_CRASH_REPORTER) &&
2939 NS_SUCCEEDED(
2940 CrashReporter::SetExceptionHandler(appData.xreDirectory))) {
2941 if (appData.crashReporterURL)
2942 CrashReporter::SetServerURL(nsDependentCString(appData.crashReporterURL));
2944 // pass some basic info from the app data
2945 if (appData.vendor)
2946 CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("Vendor"),
2947 nsDependentCString(appData.vendor));
2948 if (appData.name)
2949 CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("ProductName"),
2950 nsDependentCString(appData.name));
2951 if (appData.version)
2952 CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("Version"),
2953 nsDependentCString(appData.version));
2954 if (appData.buildID)
2955 CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("BuildID"),
2956 nsDependentCString(appData.buildID));
2957 CrashReporter::SetRestartArgs(argc, argv);
2959 // annotate other data (user id etc)
2960 nsCOMPtr<nsILocalFile> userAppDataDir;
2961 if (NS_SUCCEEDED(dirProvider.GetUserAppDataDirectory(
2962 getter_AddRefs(userAppDataDir)))) {
2963 CrashReporter::SetupExtraData(userAppDataDir,
2964 nsDependentCString(appData.buildID));
2966 // see if we have a crashreporter-override.ini in the application directory
2967 nsCOMPtr<nsIFile> overrideini;
2968 PRBool exists;
2969 static char overrideEnv[MAXPATHLEN];
2970 if (NS_SUCCEEDED(dirProvider.GetAppDir()->Clone(getter_AddRefs(overrideini))) &&
2971 NS_SUCCEEDED(overrideini->AppendNative(NS_LITERAL_CSTRING("crashreporter-override.ini"))) &&
2972 NS_SUCCEEDED(overrideini->Exists(&exists)) &&
2973 exists) {
2974 #ifdef XP_WIN
2975 nsAutoString overridePathW;
2976 overrideini->GetPath(overridePathW);
2977 NS_ConvertUTF16toUTF8 overridePath(overridePathW);
2978 #else
2979 nsCAutoString overridePath;
2980 overrideini->GetNativePath(overridePath);
2981 #endif
2983 sprintf(overrideEnv, "MOZ_CRASHREPORTER_STRINGS_OVERRIDE=%s",
2984 overridePath.get());
2985 PR_SetEnv(overrideEnv);
2989 #endif
2991 #ifdef XP_MACOSX
2992 if (PR_GetEnv("MOZ_LAUNCHED_CHILD")) {
2993 // This is needed, on relaunch, to force the OS to use the "Cocoa Dock
2994 // API". Otherwise the call to ReceiveNextEvent() below will make it
2995 // use the "Carbon Dock API". For more info see bmo bug 377166.
2996 EnsureUseCocoaDockAPI();
2998 // When the app relaunches, the original process exits. This causes
2999 // the dock tile to stop bouncing, lose the "running" triangle, and
3000 // if the tile does not permanently reside in the Dock, even disappear.
3001 // This can be confusing to the user, who is expecting the app to launch.
3002 // Calling ReceiveNextEvent without requesting any event is enough to
3003 // cause a dock tile for the child process to appear.
3004 const EventTypeSpec kFakeEventList[] = { { INT_MAX, INT_MAX } };
3005 EventRef event;
3006 ::ReceiveNextEvent(GetEventTypeCount(kFakeEventList), kFakeEventList,
3007 kEventDurationNoWait, PR_FALSE, &event);
3010 if (CheckArg("foreground")) {
3011 // The original process communicates that it was in the foreground by
3012 // adding this argument. This new process, which is taking over for
3013 // the old one, should make itself the active application.
3014 ProcessSerialNumber psn;
3015 if (::GetCurrentProcess(&psn) == noErr)
3016 ::SetFrontProcess(&psn);
3018 #endif
3020 SaveToEnv("MOZ_LAUNCHED_CHILD=");
3022 gRestartArgc = gArgc;
3023 gRestartArgv = (char**) malloc(sizeof(char*) * (gArgc + 1 + (override ? 2 : 0)));
3024 if (!gRestartArgv) return 1;
3026 int i;
3027 for (i = 0; i < gArgc; ++i) {
3028 gRestartArgv[i] = gArgv[i];
3031 // Add the -override argument back (it is removed automatically be CheckArg) if there is one
3032 if (override) {
3033 gRestartArgv[gRestartArgc++] = const_cast<char*>("-override");
3034 gRestartArgv[gRestartArgc++] = const_cast<char*>(override);
3037 gRestartArgv[gRestartArgc] = nsnull;
3040 #if defined(XP_OS2)
3041 PRBool StartOS2App(int aArgc, char **aArgv);
3042 if (!StartOS2App(gArgc, gArgv))
3043 return 1;
3044 ScopedFPHandler handler;
3045 #endif /* XP_OS2 */
3047 ar = CheckArg("safe-mode", PR_TRUE);
3048 if (ar == ARG_BAD) {
3049 PR_fprintf(PR_STDERR, "Error: argument -safe-mode is invalid when argument -osint is specified\n");
3050 return 1;
3051 } else if (ar == ARG_FOUND) {
3052 gSafeMode = PR_TRUE;
3055 #ifdef XP_MACOSX
3056 if (GetCurrentEventKeyModifiers() & optionKey)
3057 gSafeMode = PR_TRUE;
3058 #endif
3060 // Handle -no-remote command line argument. Setup the environment to
3061 // better accommodate other components and various restart scenarios.
3062 ar = CheckArg("no-remote", PR_TRUE);
3063 if (ar == ARG_BAD) {
3064 PR_fprintf(PR_STDERR, "Error: argument -a requires an application name\n");
3065 return 1;
3066 } else if (ar == ARG_FOUND) {
3067 SaveToEnv("MOZ_NO_REMOTE=1");
3070 // Handle -help and -version command line arguments.
3071 // They should return quickly, so we deal with them here.
3072 if (CheckArg("h") || CheckArg("help") || CheckArg("?")) {
3073 DumpHelp();
3074 return 0;
3077 if (CheckArg("v") || CheckArg("version")) {
3078 DumpVersion();
3079 return 0;
3082 #ifdef NS_TRACE_MALLOC
3083 gArgc = argc = NS_TraceMallocStartupArgs(gArgc, gArgv);
3084 #endif
3086 MOZ_SPLASHSCREEN_UPDATE(20);
3088 rv = XRE_InitCommandLine(gArgc, gArgv);
3089 NS_ENSURE_SUCCESS(rv, 1);
3092 // Check for -register, which registers chrome and then exits immediately.
3093 ar = CheckArg("register", PR_TRUE);
3094 if (ar == ARG_BAD) {
3095 PR_fprintf(PR_STDERR, "Error: argument -register is invalid when argument -osint is specified\n");
3096 return 1;
3097 } else if (ar == ARG_FOUND) {
3098 ScopedXPCOMStartup xpcom;
3099 rv = xpcom.Initialize();
3100 NS_ENSURE_SUCCESS(rv, 1);
3103 nsCOMPtr<nsIChromeRegistry> chromeReg =
3104 mozilla::services::GetChromeRegistryService();
3105 NS_ENSURE_TRUE(chromeReg, 1);
3107 chromeReg->CheckForNewChrome();
3109 return 0;
3112 #if defined(MOZ_WIDGET_GTK2) || defined(MOZ_ENABLE_XREMOTE)
3113 // Stash DESKTOP_STARTUP_ID in malloc'ed memory because gtk_init will clear it.
3114 #define HAVE_DESKTOP_STARTUP_ID
3115 const char* desktopStartupIDEnv = PR_GetEnv("DESKTOP_STARTUP_ID");
3116 nsCAutoString desktopStartupID;
3117 if (desktopStartupIDEnv) {
3118 desktopStartupID.Assign(desktopStartupIDEnv);
3120 #endif
3122 #if defined(MOZ_WIDGET_QT)
3123 const char* qgraphicssystemARG = NULL;
3124 ar = CheckArg("graphicssystem", PR_TRUE, &qgraphicssystemARG, PR_FALSE);
3125 if (ar == ARG_FOUND)
3126 PR_SetEnv(PR_smprintf("MOZ_QT_GRAPHICSSYSTEM=%s", qgraphicssystemARG));
3128 #ifdef MOZ_ENABLE_MEEGOTOUCH
3129 QScopedPointer<QApplication> app;
3130 if (XRE_GetProcessType() == GeckoProcessType_Default) {
3131 MozMeegoAppService *appService = new MozMeegoAppService;
3132 app.reset(new MApplication(gArgc, gArgv, appService));
3133 } else {
3134 app.reset(new QApplication(gArgc, gArgv));
3136 #else
3137 QScopedPointer<QApplication> app(new QApplication(gArgc, gArgv));
3138 #endif
3140 #if MOZ_PLATFORM_MAEMO > 5
3141 if (XRE_GetProcessType() == GeckoProcessType_Default) {
3142 // try to get the MInputContext if possible to support the MeeGo VKB
3143 QInputContext* inputContext = app->inputContext();
3144 if (inputContext && inputContext->identifierName() != "MInputContext") {
3145 QInputContext* context = QInputContextFactory::create("MInputContext",
3146 app.data());
3147 if (context)
3148 app->setInputContext(context);
3151 #endif
3152 QStringList nonQtArguments = app->arguments();
3153 gQtOnlyArgc = 1;
3154 gQtOnlyArgv = (char**) malloc(sizeof(char*)
3155 * (gRestartArgc - nonQtArguments.size() + 2));
3157 // copy binary path
3158 gQtOnlyArgv[0] = gRestartArgv[0];
3160 for (int i = 1; i < gRestartArgc; ++i) {
3161 if (!nonQtArguments.contains(gRestartArgv[i])) {
3162 // copy arguments used by Qt for later
3163 gQtOnlyArgv[gQtOnlyArgc++] = gRestartArgv[i];
3166 gQtOnlyArgv[gQtOnlyArgc] = nsnull;
3167 #endif
3168 #if defined(MOZ_WIDGET_GTK2)
3169 #ifdef MOZ_MEMORY
3170 // Disable the slice allocator, since jemalloc already uses similar layout
3171 // algorithms, and using a sub-allocator tends to increase fragmentation.
3172 // This must be done before g_thread_init() is called.
3173 g_slice_set_config(G_SLICE_CONFIG_ALWAYS_MALLOC, 1);
3174 #endif
3175 g_thread_init(NULL);
3176 // setup for private colormap. Ideally we'd like to do this
3177 // in nsAppShell::Create, but we need to get in before gtk
3178 // has been initialized to make sure everything is running
3179 // consistently.
3180 if (CheckArg("install"))
3181 gdk_rgb_set_install(TRUE);
3183 // Initialize GTK here for splash.
3185 // Open the display ourselves instead of using gtk_init, so that we can
3186 // close it without fear that one day gtk might clean up the display it
3187 // opens.
3188 if (!gtk_parse_args(&gArgc, &gArgv))
3189 return 1;
3191 // display_name is owned by gdk.
3192 const char *display_name = gdk_get_display_arg_name();
3193 if (display_name) {
3194 SaveWordToEnv("DISPLAY", nsDependentCString(display_name));
3195 } else {
3196 display_name = PR_GetEnv("DISPLAY");
3197 if (!display_name) {
3198 PR_fprintf(PR_STDERR, "Error: no display specified\n");
3199 return 1;
3202 #endif /* MOZ_WIDGET_GTK2 */
3204 #ifdef MOZ_ENABLE_XREMOTE
3205 // handle -remote now that xpcom is fired up
3207 const char* xremotearg;
3208 ar = CheckArg("remote", PR_TRUE, &xremotearg);
3209 if (ar == ARG_BAD) {
3210 PR_fprintf(PR_STDERR, "Error: -remote requires an argument\n");
3211 return 1;
3213 const char* desktopStartupIDPtr =
3214 desktopStartupID.IsEmpty() ? nsnull : desktopStartupID.get();
3215 if (ar) {
3216 return HandleRemoteArgument(xremotearg, desktopStartupIDPtr);
3219 if (!PR_GetEnv("MOZ_NO_REMOTE")) {
3220 // Try to remote the entire command line. If this fails, start up normally.
3221 RemoteResult rr = RemoteCommandLine(desktopStartupIDPtr);
3222 if (rr == REMOTE_FOUND)
3223 return 0;
3224 else if (rr == REMOTE_ARG_BAD)
3225 return 1;
3227 #endif
3229 #if defined(MOZ_WIDGET_GTK2)
3230 GdkDisplay* display = nsnull;
3231 display = gdk_display_open(display_name);
3232 if (!display) {
3233 PR_fprintf(PR_STDERR, "Error: cannot open display: %s\n", display_name);
3234 return 1;
3236 gdk_display_manager_set_default_display (gdk_display_manager_get(),
3237 display);
3239 // g_set_application_name () is only defined in glib2.2 and higher.
3240 _g_set_application_name_fn _g_set_application_name =
3241 (_g_set_application_name_fn)FindFunction("g_set_application_name");
3242 if (_g_set_application_name) {
3243 _g_set_application_name(gAppData->name);
3245 _gtk_window_set_auto_startup_notification_fn _gtk_window_set_auto_startup_notification =
3246 (_gtk_window_set_auto_startup_notification_fn)FindFunction("gtk_window_set_auto_startup_notification");
3247 if (_gtk_window_set_auto_startup_notification) {
3248 _gtk_window_set_auto_startup_notification(PR_FALSE);
3251 gtk_widget_set_default_colormap(gdk_rgb_get_colormap());
3252 #endif /* MOZ_WIDGET_GTK2 */
3253 #ifdef MOZ_X11
3254 // Do this after initializing GDK, or GDK will install its own handler.
3255 InstallX11ErrorHandler();
3256 #endif
3258 // Call the code to install our handler
3259 #ifdef MOZ_JPROF
3260 setupProfilingStuff();
3261 #endif
3263 // Try to allocate "native app support."
3264 nsCOMPtr<nsINativeAppSupport> nativeApp;
3265 rv = NS_CreateNativeAppSupport(getter_AddRefs(nativeApp));
3266 if (NS_FAILED(rv))
3267 return 1;
3269 PRBool canRun = PR_FALSE;
3270 rv = nativeApp->Start(&canRun);
3271 if (NS_FAILED(rv) || !canRun) {
3272 return 1;
3275 #if defined(MOZ_UPDATER) && !defined(ANDROID)
3276 // Check for and process any available updates
3277 nsCOMPtr<nsIFile> updRoot;
3278 PRBool persistent;
3279 rv = dirProvider.GetFile(XRE_UPDATE_ROOT_DIR, &persistent,
3280 getter_AddRefs(updRoot));
3281 // XRE_UPDATE_ROOT_DIR may fail. Fallback to appDir if failed
3282 if (NS_FAILED(rv))
3283 updRoot = dirProvider.GetAppDir();
3285 ProcessUpdates(dirProvider.GetGREDir(),
3286 dirProvider.GetAppDir(),
3287 updRoot,
3288 gRestartArgc,
3289 gRestartArgv,
3290 appData.version);
3291 #endif
3293 nsCOMPtr<nsIProfileLock> profileLock;
3294 PRBool startOffline = PR_FALSE;
3295 nsCAutoString profileName;
3297 rv = SelectProfile(getter_AddRefs(profileLock), nativeApp, &startOffline,
3298 &profileName);
3299 if (rv == NS_ERROR_LAUNCHED_CHILD_PROCESS ||
3300 rv == NS_ERROR_ABORT) return 0;
3302 if (NS_FAILED(rv)) {
3303 // We failed to choose or create profile - notify user and quit
3304 ProfileMissingDialog(nativeApp);
3305 return 1;
3308 nsCOMPtr<nsILocalFile> profD;
3309 rv = profileLock->GetDirectory(getter_AddRefs(profD));
3310 NS_ENSURE_SUCCESS(rv, 1);
3312 nsCOMPtr<nsILocalFile> profLD;
3313 rv = profileLock->GetLocalDirectory(getter_AddRefs(profLD));
3314 NS_ENSURE_SUCCESS(rv, 1);
3316 rv = dirProvider.SetProfile(profD, profLD);
3317 NS_ENSURE_SUCCESS(rv, 1);
3319 #if defined(WINCE) && defined(MOZ_SPLASHSCREEN)
3320 // give up the mutex, let other app startups happen
3321 winStartupMutex.Unlock();
3322 #endif
3324 //////////////////////// NOW WE HAVE A PROFILE ////////////////////////
3326 #ifdef MOZ_CRASHREPORTER
3327 if (appData.flags & NS_XRE_ENABLE_CRASH_REPORTER)
3328 MakeOrSetMinidumpPath(profD);
3329 #endif
3331 nsCAutoString version;
3332 BuildVersion(version);
3334 #ifdef TARGET_OS_ABI
3335 NS_NAMED_LITERAL_CSTRING(osABI, TARGET_OS_ABI);
3336 #else
3337 // No TARGET_XPCOM_ABI, but at least the OS is known
3338 NS_NAMED_LITERAL_CSTRING(osABI, OS_TARGET "_UNKNOWN");
3339 #endif
3341 // Check for version compatibility with the last version of the app this
3342 // profile was started with. The format of the version stamp is defined
3343 // by the BuildVersion function.
3344 // Also check to see if something has happened to invalidate our
3345 // fastload caches, like an extension upgrade or installation.
3347 // If we see .purgecaches, that means someone did a make.
3348 // Re-register components to catch potential changes.
3349 // We only offer this in debug builds, though.
3350 nsCOMPtr<nsILocalFile> flagFile;
3351 #ifdef DEBUG
3352 rv = NS_ERROR_FILE_NOT_FOUND;
3353 nsCOMPtr<nsIFile> fFlagFile;
3354 if (gAppData->directory) {
3355 rv = gAppData->directory->Clone(getter_AddRefs(fFlagFile));
3357 flagFile = do_QueryInterface(fFlagFile);
3358 if (flagFile) {
3359 flagFile->AppendNative(FILE_INVALIDATE_CACHES);
3361 #endif
3362 PRBool cachesOK;
3363 PRBool versionOK = CheckCompatibility(profD, version, osABI,
3364 dirProvider.GetGREDir(),
3365 gAppData->directory, flagFile,
3366 &cachesOK);
3367 if (CheckArg("purgecaches")) {
3368 cachesOK = PR_FALSE;
3370 if (PR_GetEnv("MOZ_PURGE_CACHES")) {
3371 cachesOK = PR_FALSE;
3374 // Every time a profile is loaded by a build with a different version,
3375 // it updates the compatibility.ini file saying what version last wrote
3376 // the fastload caches. On subsequent launches if the version matches,
3377 // there is no need for re-registration. If the user loads the same
3378 // profile in different builds the component registry must be
3379 // re-generated to prevent mysterious component loading failures.
3381 if (gSafeMode) {
3382 RemoveComponentRegistries(profD, profLD, PR_FALSE);
3383 WriteVersion(profD, NS_LITERAL_CSTRING("Safe Mode"), osABI,
3384 dirProvider.GetGREDir(), gAppData->directory);
3386 else if (versionOK) {
3387 if (!cachesOK) {
3388 // Remove caches, forcing component re-registration.
3389 // The new list of additional components directories is derived from
3390 // information in "extensions.ini".
3391 RemoveComponentRegistries(profD, profLD, PR_FALSE);
3393 // Rewrite compatibility.ini to remove the flag
3394 WriteVersion(profD, version, osABI,
3395 dirProvider.GetGREDir(), gAppData->directory);
3397 // Nothing need be done for the normal startup case.
3399 else {
3400 // Remove caches, forcing component re-registration
3401 // with the default set of components (this disables any potentially
3402 // troublesome incompatible XPCOM components).
3403 RemoveComponentRegistries(profD, profLD, PR_TRUE);
3405 // Write out version
3406 WriteVersion(profD, version, osABI,
3407 dirProvider.GetGREDir(), gAppData->directory);
3410 #ifdef DEBUG
3411 if (flagFile) {
3412 flagFile->Remove(PR_TRUE);
3414 #endif
3415 PRBool appInitiatedRestart = PR_FALSE;
3417 MOZ_SPLASHSCREEN_UPDATE(30);
3419 NS_TIME_FUNCTION_MARK("Next: ScopedXPCOMStartup");
3421 NS_TIME_FUNCTION_MARK("ScopedXPCOMStartup");
3423 // Allows the user to forcefully bypass the restart process at their
3424 // own risk. Useful for debugging or for tinderboxes where child
3425 // processes can be problematic.
3427 // Start the real application
3428 ScopedXPCOMStartup xpcom;
3429 rv = xpcom.Initialize();
3430 NS_TIME_FUNCTION_MARK("ScopedXPCOMStartup: Initialize");
3431 NS_ENSURE_SUCCESS(rv, 1);
3434 #ifdef NS_FUNCTION_TIMER
3435 // initialize some common services, so we don't pay the cost for these at odd times later on;
3436 // SetWindowCreator -> ChromeRegistry -> IOService -> SocketTransportService -> (nspr wspm init), Prefs
3438 nsCOMPtr<nsISupports> comp;
3440 comp = do_GetService("@mozilla.org/preferences-service;1");
3441 NS_TIME_FUNCTION_MARK("Pref Service");
3443 comp = do_GetService("@mozilla.org/network/socket-transport-service;1");
3444 NS_TIME_FUNCTION_MARK("Socket Transport Service");
3446 comp = do_GetService("@mozilla.org/network/dns-service;1");
3447 NS_TIME_FUNCTION_MARK("DNS Service");
3449 comp = do_GetService("@mozilla.org/network/io-service;1");
3450 NS_TIME_FUNCTION_MARK("IO Service");
3452 comp = do_GetService("@mozilla.org/chrome/chrome-registry;1");
3453 NS_TIME_FUNCTION_MARK("Chrome Registry Service");
3455 comp = do_GetService("@mozilla.org/focus-event-suppressor-service;1");
3456 NS_TIME_FUNCTION_MARK("Focus Event Suppressor Service");
3458 #endif
3460 rv = xpcom.SetWindowCreator(nativeApp);
3461 NS_TIME_FUNCTION_MARK("ScopedXPCOMStartup: SetWindowCreator");
3462 NS_ENSURE_SUCCESS(rv, 1);
3464 NS_TIME_FUNCTION_MARK("ScopedXPCOMStartup: Done");
3466 #ifdef MOZ_CRASHREPORTER
3467 // tell the crash reporter to also send the release channel
3468 nsCOMPtr<nsIPrefService> prefs = do_GetService("@mozilla.org/preferences-service;1", &rv);
3469 if (NS_SUCCEEDED(rv)) {
3470 nsCOMPtr<nsIPrefBranch> defaultPrefBranch;
3471 rv = prefs->GetDefaultBranch(nsnull, getter_AddRefs(defaultPrefBranch));
3473 if (NS_SUCCEEDED(rv)) {
3474 nsXPIDLCString sval;
3475 rv = defaultPrefBranch->GetCharPref("app.update.channel", getter_Copies(sval));
3476 if (NS_SUCCEEDED(rv)) {
3477 CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("ReleaseChannel"),
3478 sval);
3482 #endif
3484 NS_TIME_FUNCTION_MARK("Next: AppStartup");
3487 if (startOffline) {
3488 nsCOMPtr<nsIIOService2> io (do_GetService("@mozilla.org/network/io-service;1"));
3489 NS_ENSURE_TRUE(io, 1);
3490 io->SetManageOfflineStatus(PR_FALSE);
3491 io->SetOffline(PR_TRUE);
3495 NS_TIMELINE_ENTER("startupNotifier");
3496 nsCOMPtr<nsIObserver> startupNotifier
3497 (do_CreateInstance(NS_APPSTARTUPNOTIFIER_CONTRACTID, &rv));
3498 NS_ENSURE_SUCCESS(rv, 1);
3500 startupNotifier->Observe(nsnull, APPSTARTUP_TOPIC, nsnull);
3501 NS_TIMELINE_LEAVE("startupNotifier");
3504 NS_TIME_FUNCTION_MARK("Finished startupNotifier");
3506 nsCOMPtr<nsIAppStartup2> appStartup
3507 (do_GetService(NS_APPSTARTUP_CONTRACTID));
3508 NS_ENSURE_TRUE(appStartup, 1);
3510 NS_TIME_FUNCTION_MARK("Created AppStartup");
3512 if (gDoMigration) {
3513 nsCOMPtr<nsIFile> file;
3514 dirProvider.GetAppDir()->Clone(getter_AddRefs(file));
3515 file->AppendNative(NS_LITERAL_CSTRING("override.ini"));
3516 nsINIParser parser;
3517 nsCOMPtr<nsILocalFile> localFile(do_QueryInterface(file));
3518 nsresult rv = parser.Init(localFile);
3519 if (NS_SUCCEEDED(rv)) {
3520 nsCAutoString buf;
3521 rv = parser.GetString("XRE", "EnableProfileMigrator", buf);
3522 if (NS_SUCCEEDED(rv)) {
3523 if (buf[0] == '0' || buf[0] == 'f' || buf[0] == 'F') {
3524 gDoMigration = PR_FALSE;
3530 // Profile Migration
3531 if (gAppData->flags & NS_XRE_ENABLE_PROFILE_MIGRATOR && gDoMigration) {
3532 gDoMigration = PR_FALSE;
3533 nsCOMPtr<nsIProfileMigrator> pm
3534 (do_CreateInstance(NS_PROFILEMIGRATOR_CONTRACTID));
3535 if (pm)
3536 pm->Migrate(&dirProvider);
3539 NS_TIME_FUNCTION_MARK("Profile migration");
3541 dirProvider.DoStartup();
3543 NS_TIME_FUNCTION_MARK("dirProvider.DoStartup() (profile-after-change)");
3545 PRBool shuttingDown = PR_FALSE;
3546 appStartup->GetShuttingDown(&shuttingDown);
3548 nsCOMPtr<nsICommandLineRunner> cmdLine;
3550 nsCOMPtr<nsIFile> workingDir;
3551 rv = NS_GetSpecialDirectory(NS_OS_CURRENT_WORKING_DIR, getter_AddRefs(workingDir));
3552 NS_ENSURE_SUCCESS(rv, 1);
3554 if (!shuttingDown) {
3555 cmdLine = do_CreateInstance("@mozilla.org/toolkit/command-line;1");
3556 NS_ENSURE_TRUE(cmdLine, 1);
3558 rv = cmdLine->Init(gArgc, gArgv,
3559 workingDir, nsICommandLine::STATE_INITIAL_LAUNCH);
3560 NS_ENSURE_SUCCESS(rv, 1);
3562 /* Special-case services that need early access to the command
3563 line. */
3564 nsCOMPtr<nsIObserverService> obsService =
3565 mozilla::services::GetObserverService();
3566 if (obsService) {
3567 obsService->NotifyObservers(cmdLine, "command-line-startup", nsnull);
3570 NS_TIME_FUNCTION_MARK("Early command line init");
3572 NS_TIME_FUNCTION_MARK("Next: prepare for Run");
3575 SaveStateForAppInitiatedRestart();
3577 // clear out any environment variables which may have been set
3578 // during the relaunch process now that we know we won't be relaunching.
3579 SaveToEnv("XRE_PROFILE_PATH=");
3580 SaveToEnv("XRE_PROFILE_LOCAL_PATH=");
3581 SaveToEnv("XRE_PROFILE_NAME=");
3582 SaveToEnv("XRE_START_OFFLINE=");
3583 SaveToEnv("XRE_IMPORT_PROFILES=");
3584 SaveToEnv("NO_EM_RESTART=");
3585 SaveToEnv("XUL_APP_FILE=");
3586 SaveToEnv("XRE_BINARY_PATH=");
3588 NS_TIME_FUNCTION_MARK("env munging");
3590 if (!shuttingDown) {
3591 NS_TIME_FUNCTION_MARK("Next: CreateHiddenWindow");
3593 NS_TIMELINE_ENTER("appStartup->CreateHiddenWindow");
3594 rv = appStartup->CreateHiddenWindow();
3595 NS_TIMELINE_LEAVE("appStartup->CreateHiddenWindow");
3596 NS_ENSURE_SUCCESS(rv, 1);
3598 MOZ_SPLASHSCREEN_UPDATE(50);
3600 #if defined(HAVE_DESKTOP_STARTUP_ID) && defined(MOZ_WIDGET_GTK2)
3601 nsRefPtr<nsGTKToolkit> toolkit = GetGTKToolkit();
3602 if (toolkit && !desktopStartupID.IsEmpty()) {
3603 toolkit->SetDesktopStartupID(desktopStartupID);
3605 #endif
3607 #ifdef XP_MACOSX
3608 // we re-initialize the command-line service and do appleevents munging
3609 // after we are sure that we're not restarting
3610 cmdLine = do_CreateInstance("@mozilla.org/toolkit/command-line;1");
3611 NS_ENSURE_TRUE(cmdLine, 1);
3613 CommandLineServiceMac::SetupMacCommandLine(gArgc, gArgv, PR_FALSE);
3615 rv = cmdLine->Init(gArgc, gArgv,
3616 workingDir, nsICommandLine::STATE_INITIAL_LAUNCH);
3617 NS_ENSURE_SUCCESS(rv, 1);
3619 // Set up ability to respond to system (Apple) events.
3620 SetupMacApplicationDelegate();
3621 #endif
3623 MOZ_SPLASHSCREEN_UPDATE(70);
3625 nsCOMPtr<nsIObserverService> obsService =
3626 mozilla::services::GetObserverService();
3627 if (obsService)
3628 obsService->NotifyObservers(nsnull, "final-ui-startup", nsnull);
3630 NS_TIME_FUNCTION_MARK("final-ui-startup done");
3632 appStartup->GetShuttingDown(&shuttingDown);
3635 if (!shuttingDown) {
3636 rv = cmdLine->Run();
3637 NS_ENSURE_SUCCESS_LOG(rv, 1);
3639 appStartup->GetShuttingDown(&shuttingDown);
3642 #ifdef MOZ_ENABLE_XREMOTE
3643 nsCOMPtr<nsIRemoteService> remoteService;
3644 #endif /* MOZ_ENABLE_XREMOTE */
3645 if (!shuttingDown) {
3646 #ifdef MOZ_ENABLE_XREMOTE
3647 // if we have X remote support, start listening for requests on the
3648 // proxy window.
3649 remoteService = do_GetService("@mozilla.org/toolkit/remote-service;1");
3650 if (remoteService)
3651 remoteService->Startup(gAppData->name,
3652 PromiseFlatCString(profileName).get());
3653 #endif /* MOZ_ENABLE_XREMOTE */
3655 nativeApp->Enable();
3658 NS_TIME_FUNCTION_MARK("Next: Run");
3660 NS_TIME_FUNCTION_MARK("appStartup->Run");
3662 MOZ_SPLASHSCREEN_UPDATE(90);
3664 NS_TIMELINE_ENTER("appStartup->Run");
3665 rv = appStartup->Run();
3666 NS_TIMELINE_LEAVE("appStartup->Run");
3667 if (NS_FAILED(rv)) {
3668 NS_ERROR("failed to run appstartup");
3669 gLogConsoleErrors = PR_TRUE;
3673 NS_TIME_FUNCTION_MARK("Next: Finish");
3675 NS_TIME_FUNCTION_MARK("appStartup->Run done");
3677 // Check for an application initiated restart. This is one that
3678 // corresponds to nsIAppStartup.quit(eRestart)
3679 if (rv == NS_SUCCESS_RESTART_APP)
3680 appInitiatedRestart = PR_TRUE;
3682 if (!shuttingDown) {
3683 #ifdef MOZ_ENABLE_XREMOTE
3684 // shut down the x remote proxy window
3685 if (remoteService)
3686 remoteService->Shutdown();
3687 #endif /* MOZ_ENABLE_XREMOTE */
3690 #ifdef MOZ_TIMELINE
3691 // Make sure we print this out even if timeline is runtime disabled
3692 if (NS_FAILED(NS_TIMELINE_LEAVE("main1")))
3693 NS_TimelineForceMark("...main1");
3694 #endif
3698 // unlock the profile after ScopedXPCOMStartup object (xpcom)
3699 // has gone out of scope. see bug #386739 for more details
3700 profileLock->Unlock();
3702 // Restart the app after XPCOM has been shut down cleanly.
3703 if (appInitiatedRestart) {
3704 MOZ_SPLASHSCREEN_UPDATE(90);
3706 RestoreStateForAppInitiatedRestart();
3708 // Ensure that these environment variables are set:
3709 SaveFileToEnvIfUnset("XRE_PROFILE_PATH", profD);
3710 SaveFileToEnvIfUnset("XRE_PROFILE_LOCAL_PATH", profLD);
3711 SaveWordToEnvIfUnset("XRE_PROFILE_NAME", profileName);
3713 #ifdef XP_MACOSX
3714 if (gBinaryPath) {
3715 static char kEnvVar[MAXPATHLEN];
3716 sprintf(kEnvVar, "XRE_BINARY_PATH=%s", gBinaryPath);
3717 PR_SetEnv(kEnvVar);
3719 #endif
3721 #if defined(HAVE_DESKTOP_STARTUP_ID) && defined(MOZ_WIDGET_GTK2)
3722 if (!desktopStartupID.IsEmpty()) {
3723 nsCAutoString desktopStartupEnv;
3724 desktopStartupEnv.AssignLiteral("DESKTOP_STARTUP_ID=");
3725 desktopStartupEnv.Append(desktopStartupID);
3726 // Leak it with extreme prejudice!
3727 PR_SetEnv(ToNewCString(desktopStartupEnv));
3729 #endif
3731 #ifdef MOZ_WIDGET_GTK2
3732 MOZ_gdk_display_close(display);
3733 #endif
3735 rv = LaunchChild(nativeApp, PR_TRUE);
3737 #ifdef MOZ_CRASHREPORTER
3738 if (appData.flags & NS_XRE_ENABLE_CRASH_REPORTER)
3739 CrashReporter::UnsetExceptionHandler();
3740 #endif
3742 return rv == NS_ERROR_LAUNCHED_CHILD_PROCESS ? 0 : 1;
3745 #ifdef MOZ_WIDGET_GTK2
3746 // gdk_display_close also calls gdk_display_manager_set_default_display
3747 // appropriately when necessary.
3748 MOZ_gdk_display_close(display);
3749 #endif
3752 #ifdef MOZ_CRASHREPORTER
3753 if (appData.flags & NS_XRE_ENABLE_CRASH_REPORTER)
3754 CrashReporter::UnsetExceptionHandler();
3755 #endif
3757 XRE_DeinitCommandLine();
3759 return NS_FAILED(rv) ? 1 : 0;
3762 nsresult
3763 XRE_InitCommandLine(int aArgc, char* aArgv[])
3765 nsresult rv = NS_OK;
3767 #if defined(MOZ_IPC)
3769 #if defined(OS_WIN)
3770 CommandLine::Init(aArgc, aArgv);
3771 #else
3773 // these leak on error, but that's OK: we'll just exit()
3774 char** canonArgs = new char*[aArgc];
3776 // get the canonical version of the binary's path
3777 nsCOMPtr<nsILocalFile> binFile;
3778 rv = XRE_GetBinaryPath(aArgv[0], getter_AddRefs(binFile));
3779 if (NS_FAILED(rv))
3780 return NS_ERROR_FAILURE;
3782 nsCAutoString canonBinPath;
3783 rv = binFile->GetNativePath(canonBinPath);
3784 if (NS_FAILED(rv))
3785 return NS_ERROR_FAILURE;
3787 canonArgs[0] = strdup(canonBinPath.get());
3789 for (int i = 1; i < aArgc; ++i) {
3790 if (aArgv[i]) {
3791 canonArgs[i] = strdup(aArgv[i]);
3795 NS_ASSERTION(!CommandLine::IsInitialized(), "Bad news!");
3796 CommandLine::Init(aArgc, canonArgs);
3798 for (int i = 0; i < aArgc; ++i)
3799 free(canonArgs[i]);
3800 delete[] canonArgs;
3801 #endif
3802 #endif
3804 #ifdef MOZ_OMNIJAR
3805 const char *omnijarPath = nsnull;
3806 ArgResult ar = CheckArg("omnijar", PR_FALSE, &omnijarPath);
3807 if (ar == ARG_BAD) {
3808 PR_fprintf(PR_STDERR, "Error: argument -omnijar requires an omnijar path\n");
3809 return NS_ERROR_FAILURE;
3812 if (!omnijarPath)
3813 return rv;
3815 nsCOMPtr<nsILocalFile> omnijar;
3816 rv = NS_NewNativeLocalFile(nsDependentCString(omnijarPath), PR_TRUE,
3817 getter_AddRefs(omnijar));
3818 if (NS_SUCCEEDED(rv))
3819 mozilla::SetOmnijar(omnijar);
3820 #endif
3822 return rv;
3825 nsresult
3826 XRE_DeinitCommandLine()
3828 nsresult rv = NS_OK;
3830 #if defined(MOZ_IPC)
3831 CommandLine::Terminate();
3832 #endif
3834 return rv;
3837 GeckoProcessType
3838 XRE_GetProcessType()
3840 #ifdef MOZ_IPC
3841 return mozilla::startup::sChildProcessType;
3842 #else
3843 return GeckoProcessType_Default;
3844 #endif
3847 void
3848 SetupErrorHandling(const char* progname)
3850 #ifdef XP_WIN
3851 /* On Windows XPSP3 and Windows Vista if DEP is configured off-by-default
3852 we still want DEP protection: enable it explicitly and programmatically.
3854 This function is not available on WinXPSP2 so we dynamically load it.
3857 HMODULE kernel32 = GetModuleHandleW(L"kernel32.dll");
3858 SetProcessDEPPolicyFunc _SetProcessDEPPolicy =
3859 (SetProcessDEPPolicyFunc) GetProcAddress(kernel32, "SetProcessDEPPolicy");
3860 if (_SetProcessDEPPolicy)
3861 _SetProcessDEPPolicy(PROCESS_DEP_ENABLE);
3862 #endif
3864 #if defined (XP_WIN32) && !defined (WINCE)
3865 // Suppress the "DLL Foo could not be found" dialog, such that if dependent
3866 // libraries (such as GDI+) are not preset, we gracefully fail to load those
3867 // XPCOM components, instead of being ungraceful.
3868 UINT realMode = SetErrorMode(0);
3869 realMode |= SEM_FAILCRITICALERRORS;
3870 // If XRE_NO_WINDOWS_CRASH_DIALOG is set, suppress displaying the "This
3871 // application has crashed" dialog box. This is mainly useful for
3872 // automated testing environments, e.g. tinderbox, where there's no need
3873 // for a dozen of the dialog boxes to litter the console
3874 if (getenv("XRE_NO_WINDOWS_CRASH_DIALOG"))
3875 realMode |= SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX;
3877 SetErrorMode(realMode);
3879 #endif
3881 #ifndef XP_OS2
3882 InstallSignalHandlers(progname);
3883 #endif
3885 #ifndef WINCE
3886 // Unbuffer stdout, needed for tinderbox tests.
3887 setbuf(stdout, 0);
3888 #endif
3890 #if defined(FREEBSD)
3891 // Disable all SIGFPE's on FreeBSD, as it has non-IEEE-conformant fp
3892 // trap behavior that trips up on floating-point tests performed by
3893 // the JS engine. See bugzilla bug 9967 details.
3894 fpsetmask(0);
3895 #endif