toolkit/xre/nsAppRunner.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

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

mercurial