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