Coverage Report

Created: 2018-09-25 14:53

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