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