browser/app/nsBrowserApp.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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 #include "nsXULAppAPI.h"
michael@0 7 #include "mozilla/AppData.h"
michael@0 8 #include "application.ini.h"
michael@0 9 #include "nsXPCOMGlue.h"
michael@0 10 #if defined(XP_WIN)
michael@0 11 #include <windows.h>
michael@0 12 #include <stdlib.h>
michael@0 13 #include <io.h>
michael@0 14 #include <fcntl.h>
michael@0 15 #elif defined(XP_UNIX)
michael@0 16 #include <sys/resource.h>
michael@0 17 #include <time.h>
michael@0 18 #include <unistd.h>
michael@0 19 #endif
michael@0 20
michael@0 21 #ifdef XP_MACOSX
michael@0 22 #include <mach/mach_time.h>
michael@0 23 #include "MacQuirks.h"
michael@0 24 #endif
michael@0 25
michael@0 26 #include <stdio.h>
michael@0 27 #include <stdarg.h>
michael@0 28 #include <time.h>
michael@0 29
michael@0 30 #include "nsCOMPtr.h"
michael@0 31 #include "nsIFile.h"
michael@0 32 #include "nsStringGlue.h"
michael@0 33
michael@0 34 // Easy access to a five second startup delay used to get
michael@0 35 // a debugger attached in the metro environment.
michael@0 36 // #define DEBUG_delay_start_metro
michael@0 37
michael@0 38 #ifdef XP_WIN
michael@0 39 // we want a wmain entry point
michael@0 40 #include "nsWindowsWMain.cpp"
michael@0 41 #define snprintf _snprintf
michael@0 42 #define strcasecmp _stricmp
michael@0 43 #endif
michael@0 44 #include "BinaryPath.h"
michael@0 45
michael@0 46 #include "nsXPCOMPrivate.h" // for MAXPATHLEN and XPCOM_DLL
michael@0 47
michael@0 48 #include "mozilla/Telemetry.h"
michael@0 49 #include "mozilla/WindowsDllBlocklist.h"
michael@0 50
michael@0 51 using namespace mozilla;
michael@0 52
michael@0 53 #define kDesktopFolder "browser"
michael@0 54 #define kMetroFolder "metro"
michael@0 55 #define kMetroAppIniFilename "metroapp.ini"
michael@0 56 #ifdef XP_WIN
michael@0 57 #define kMetroTestFile "tests.ini"
michael@0 58 const char* kMetroConsoleIdParam = "testconsoleid=";
michael@0 59 #endif
michael@0 60
michael@0 61 static void Output(const char *fmt, ... )
michael@0 62 {
michael@0 63 va_list ap;
michael@0 64 va_start(ap, fmt);
michael@0 65
michael@0 66 #ifndef XP_WIN
michael@0 67 vfprintf(stderr, fmt, ap);
michael@0 68 #else
michael@0 69 char msg[2048];
michael@0 70 vsnprintf_s(msg, _countof(msg), _TRUNCATE, fmt, ap);
michael@0 71
michael@0 72 wchar_t wide_msg[2048];
michael@0 73 MultiByteToWideChar(CP_UTF8,
michael@0 74 0,
michael@0 75 msg,
michael@0 76 -1,
michael@0 77 wide_msg,
michael@0 78 _countof(wide_msg));
michael@0 79 #if MOZ_WINCONSOLE
michael@0 80 fwprintf_s(stderr, wide_msg);
michael@0 81 #else
michael@0 82 // Linking user32 at load-time interferes with the DLL blocklist (bug 932100).
michael@0 83 // This is a rare codepath, so we can load user32 at run-time instead.
michael@0 84 HMODULE user32 = LoadLibraryW(L"user32.dll");
michael@0 85 if (user32) {
michael@0 86 decltype(MessageBoxW)* messageBoxW =
michael@0 87 (decltype(MessageBoxW)*) GetProcAddress(user32, "MessageBoxW");
michael@0 88 if (messageBoxW) {
michael@0 89 messageBoxW(nullptr, wide_msg, L"Firefox", MB_OK
michael@0 90 | MB_ICONERROR
michael@0 91 | MB_SETFOREGROUND);
michael@0 92 }
michael@0 93 FreeLibrary(user32);
michael@0 94 }
michael@0 95 #endif
michael@0 96 #endif
michael@0 97
michael@0 98 va_end(ap);
michael@0 99 }
michael@0 100
michael@0 101 /**
michael@0 102 * Return true if |arg| matches the given argument name.
michael@0 103 */
michael@0 104 static bool IsArg(const char* arg, const char* s)
michael@0 105 {
michael@0 106 if (*arg == '-')
michael@0 107 {
michael@0 108 if (*++arg == '-')
michael@0 109 ++arg;
michael@0 110 return !strcasecmp(arg, s);
michael@0 111 }
michael@0 112
michael@0 113 #if defined(XP_WIN)
michael@0 114 if (*arg == '/')
michael@0 115 return !strcasecmp(++arg, s);
michael@0 116 #endif
michael@0 117
michael@0 118 return false;
michael@0 119 }
michael@0 120
michael@0 121 #ifdef XP_WIN
michael@0 122 /*
michael@0 123 * AttachToTestHarness - Windows helper for when we are running
michael@0 124 * in the immersive environment. Firefox is launched by Windows in
michael@0 125 * response to a request by metrotestharness, which is launched by
michael@0 126 * runtests.py. As such stdout in fx doesn't point to the right
michael@0 127 * stream. This helper touches up stdout such that test output gets
michael@0 128 * routed to a named pipe metrotestharness creates and dumps to its
michael@0 129 * stdout.
michael@0 130 */
michael@0 131 static void AttachToTestHarness()
michael@0 132 {
michael@0 133 // attach to the metrotestharness named logging pipe
michael@0 134 HANDLE winOut = CreateFileA("\\\\.\\pipe\\metrotestharness",
michael@0 135 GENERIC_WRITE,
michael@0 136 FILE_SHARE_WRITE, 0,
michael@0 137 OPEN_EXISTING, 0, 0);
michael@0 138
michael@0 139 if (winOut == INVALID_HANDLE_VALUE) {
michael@0 140 OutputDebugStringW(L"Could not create named logging pipe.\n");
michael@0 141 return;
michael@0 142 }
michael@0 143
michael@0 144 // Set the c runtime handle
michael@0 145 int stdOut = _open_osfhandle((intptr_t)winOut, _O_APPEND);
michael@0 146 if (stdOut == -1) {
michael@0 147 OutputDebugStringW(L"Could not open c-runtime handle.\n");
michael@0 148 return;
michael@0 149 }
michael@0 150 FILE *fp = _fdopen(stdOut, "a");
michael@0 151 *stdout = *fp;
michael@0 152 }
michael@0 153 #endif
michael@0 154
michael@0 155 XRE_GetFileFromPathType XRE_GetFileFromPath;
michael@0 156 XRE_CreateAppDataType XRE_CreateAppData;
michael@0 157 XRE_FreeAppDataType XRE_FreeAppData;
michael@0 158 XRE_TelemetryAccumulateType XRE_TelemetryAccumulate;
michael@0 159 XRE_StartupTimelineRecordType XRE_StartupTimelineRecord;
michael@0 160 XRE_mainType XRE_main;
michael@0 161 XRE_StopLateWriteChecksType XRE_StopLateWriteChecks;
michael@0 162
michael@0 163 static const nsDynamicFunctionLoad kXULFuncs[] = {
michael@0 164 { "XRE_GetFileFromPath", (NSFuncPtr*) &XRE_GetFileFromPath },
michael@0 165 { "XRE_CreateAppData", (NSFuncPtr*) &XRE_CreateAppData },
michael@0 166 { "XRE_FreeAppData", (NSFuncPtr*) &XRE_FreeAppData },
michael@0 167 { "XRE_TelemetryAccumulate", (NSFuncPtr*) &XRE_TelemetryAccumulate },
michael@0 168 { "XRE_StartupTimelineRecord", (NSFuncPtr*) &XRE_StartupTimelineRecord },
michael@0 169 { "XRE_main", (NSFuncPtr*) &XRE_main },
michael@0 170 { "XRE_StopLateWriteChecks", (NSFuncPtr*) &XRE_StopLateWriteChecks },
michael@0 171 { nullptr, nullptr }
michael@0 172 };
michael@0 173
michael@0 174 static int do_main(int argc, char* argv[], nsIFile *xreDirectory)
michael@0 175 {
michael@0 176 nsCOMPtr<nsIFile> appini;
michael@0 177 nsresult rv;
michael@0 178 uint32_t mainFlags = 0;
michael@0 179
michael@0 180 // Allow firefox.exe to launch XULRunner apps via -app <application.ini>
michael@0 181 // Note that -app must be the *first* argument.
michael@0 182 const char *appDataFile = getenv("XUL_APP_FILE");
michael@0 183 if (appDataFile && *appDataFile) {
michael@0 184 rv = XRE_GetFileFromPath(appDataFile, getter_AddRefs(appini));
michael@0 185 if (NS_FAILED(rv)) {
michael@0 186 Output("Invalid path found: '%s'", appDataFile);
michael@0 187 return 255;
michael@0 188 }
michael@0 189 }
michael@0 190 else if (argc > 1 && IsArg(argv[1], "app")) {
michael@0 191 if (argc == 2) {
michael@0 192 Output("Incorrect number of arguments passed to -app");
michael@0 193 return 255;
michael@0 194 }
michael@0 195
michael@0 196 rv = XRE_GetFileFromPath(argv[2], getter_AddRefs(appini));
michael@0 197 if (NS_FAILED(rv)) {
michael@0 198 Output("application.ini path not recognized: '%s'", argv[2]);
michael@0 199 return 255;
michael@0 200 }
michael@0 201
michael@0 202 char appEnv[MAXPATHLEN];
michael@0 203 snprintf(appEnv, MAXPATHLEN, "XUL_APP_FILE=%s", argv[2]);
michael@0 204 if (putenv(appEnv)) {
michael@0 205 Output("Couldn't set %s.\n", appEnv);
michael@0 206 return 255;
michael@0 207 }
michael@0 208 argv[2] = argv[0];
michael@0 209 argv += 2;
michael@0 210 argc -= 2;
michael@0 211 }
michael@0 212
michael@0 213 if (appini) {
michael@0 214 nsXREAppData *appData;
michael@0 215 rv = XRE_CreateAppData(appini, &appData);
michael@0 216 if (NS_FAILED(rv)) {
michael@0 217 Output("Couldn't read application.ini");
michael@0 218 return 255;
michael@0 219 }
michael@0 220 // xreDirectory already has a refcount from NS_NewLocalFile
michael@0 221 appData->xreDirectory = xreDirectory;
michael@0 222 int result = XRE_main(argc, argv, appData, mainFlags);
michael@0 223 XRE_FreeAppData(appData);
michael@0 224 return result;
michael@0 225 }
michael@0 226
michael@0 227 bool metroOnDesktop = false;
michael@0 228
michael@0 229 #ifdef MOZ_METRO
michael@0 230 if (argc > 1) {
michael@0 231 // This command-line flag is passed to our executable when it is to be
michael@0 232 // launched in metro mode (i.e. our EXE is registered as the default
michael@0 233 // browser and the user has tapped our EXE's tile)
michael@0 234 if (IsArg(argv[1], "ServerName:DefaultBrowserServer")) {
michael@0 235 mainFlags = XRE_MAIN_FLAG_USE_METRO;
michael@0 236 argv[1] = argv[0];
michael@0 237 argv++;
michael@0 238 argc--;
michael@0 239 } else if (IsArg(argv[1], "BackgroundSessionClosed")) {
michael@0 240 // This command line flag is used for indirect shutdowns, the OS
michael@0 241 // relaunches Metro Firefox with this command line arg.
michael@0 242 mainFlags = XRE_MAIN_FLAG_USE_METRO;
michael@0 243 } else {
michael@0 244 #ifndef RELEASE_BUILD
michael@0 245 // This command-line flag is used to test the metro browser in a desktop
michael@0 246 // environment.
michael@0 247 for (int idx = 1; idx < argc; idx++) {
michael@0 248 if (IsArg(argv[idx], "metrodesktop")) {
michael@0 249 metroOnDesktop = true;
michael@0 250 // Disable crash reporting when running in metrodesktop mode.
michael@0 251 char crashSwitch[] = "MOZ_CRASHREPORTER_DISABLE=1";
michael@0 252 putenv(crashSwitch);
michael@0 253 break;
michael@0 254 }
michael@0 255 }
michael@0 256 #endif
michael@0 257 }
michael@0 258 }
michael@0 259 #endif
michael@0 260
michael@0 261 // Desktop browser launch
michael@0 262 if (mainFlags != XRE_MAIN_FLAG_USE_METRO && !metroOnDesktop) {
michael@0 263 ScopedAppData appData(&sAppData);
michael@0 264 nsCOMPtr<nsIFile> exeFile;
michael@0 265 rv = mozilla::BinaryPath::GetFile(argv[0], getter_AddRefs(exeFile));
michael@0 266 if (NS_FAILED(rv)) {
michael@0 267 Output("Couldn't find the application directory.\n");
michael@0 268 return 255;
michael@0 269 }
michael@0 270
michael@0 271 nsCOMPtr<nsIFile> greDir;
michael@0 272 exeFile->GetParent(getter_AddRefs(greDir));
michael@0 273
michael@0 274 nsCOMPtr<nsIFile> appSubdir;
michael@0 275 greDir->Clone(getter_AddRefs(appSubdir));
michael@0 276 appSubdir->Append(NS_LITERAL_STRING(kDesktopFolder));
michael@0 277
michael@0 278 SetStrongPtr(appData.directory, static_cast<nsIFile*>(appSubdir.get()));
michael@0 279 // xreDirectory already has a refcount from NS_NewLocalFile
michael@0 280 appData.xreDirectory = xreDirectory;
michael@0 281
michael@0 282 return XRE_main(argc, argv, &appData, mainFlags);
michael@0 283 }
michael@0 284
michael@0 285 // Metro browser launch
michael@0 286 #ifdef MOZ_METRO
michael@0 287 nsCOMPtr<nsIFile> iniFile, appSubdir;
michael@0 288
michael@0 289 xreDirectory->Clone(getter_AddRefs(iniFile));
michael@0 290 xreDirectory->Clone(getter_AddRefs(appSubdir));
michael@0 291
michael@0 292 iniFile->Append(NS_LITERAL_STRING(kMetroFolder));
michael@0 293 iniFile->Append(NS_LITERAL_STRING(kMetroAppIniFilename));
michael@0 294
michael@0 295 appSubdir->Append(NS_LITERAL_STRING(kMetroFolder));
michael@0 296
michael@0 297 nsAutoCString path;
michael@0 298 if (NS_FAILED(iniFile->GetNativePath(path))) {
michael@0 299 Output("Couldn't get ini file path.\n");
michael@0 300 return 255;
michael@0 301 }
michael@0 302
michael@0 303 nsXREAppData *appData;
michael@0 304 rv = XRE_CreateAppData(iniFile, &appData);
michael@0 305 if (NS_FAILED(rv) || !appData) {
michael@0 306 Output("Couldn't read application.ini");
michael@0 307 return 255;
michael@0 308 }
michael@0 309
michael@0 310 SetStrongPtr(appData->directory, static_cast<nsIFile*>(appSubdir.get()));
michael@0 311 // xreDirectory already has a refcount from NS_NewLocalFile
michael@0 312 appData->xreDirectory = xreDirectory;
michael@0 313
michael@0 314 #ifdef XP_WIN
michael@0 315 if (!metroOnDesktop) {
michael@0 316 nsCOMPtr<nsIFile> testFile;
michael@0 317
michael@0 318 xreDirectory->Clone(getter_AddRefs(testFile));
michael@0 319 testFile->Append(NS_LITERAL_STRING(kMetroTestFile));
michael@0 320
michael@0 321 nsAutoCString path;
michael@0 322 if (NS_FAILED(testFile->GetNativePath(path))) {
michael@0 323 Output("Couldn't get test file path.\n");
michael@0 324 return 255;
michael@0 325 }
michael@0 326
michael@0 327 // Check for a metro test harness command line args file
michael@0 328 HANDLE hTestFile = CreateFileA(path.get(),
michael@0 329 GENERIC_READ,
michael@0 330 0, nullptr, OPEN_EXISTING,
michael@0 331 FILE_ATTRIBUTE_NORMAL,
michael@0 332 nullptr);
michael@0 333 if (hTestFile != INVALID_HANDLE_VALUE) {
michael@0 334 // Typical test harness command line args string is around 100 bytes.
michael@0 335 char buffer[1024];
michael@0 336 memset(buffer, 0, sizeof(buffer));
michael@0 337 DWORD bytesRead = 0;
michael@0 338 if (!ReadFile(hTestFile, (VOID*)buffer, sizeof(buffer)-1,
michael@0 339 &bytesRead, nullptr) || !bytesRead) {
michael@0 340 CloseHandle(hTestFile);
michael@0 341 printf("failed to read test file '%s'", testFile);
michael@0 342 return -1;
michael@0 343 }
michael@0 344 CloseHandle(hTestFile);
michael@0 345
michael@0 346 // Build new args array
michael@0 347 char* newArgv[20];
michael@0 348 int newArgc = 1;
michael@0 349
michael@0 350 memset(newArgv, 0, sizeof(newArgv));
michael@0 351
michael@0 352 char* ptr = buffer;
michael@0 353 newArgv[0] = ptr;
michael@0 354 while (*ptr != '\0' &&
michael@0 355 (ptr - buffer) < sizeof(buffer) &&
michael@0 356 newArgc < ARRAYSIZE(newArgv)) {
michael@0 357 if (isspace(*ptr)) {
michael@0 358 *ptr = '\0';
michael@0 359 ptr++;
michael@0 360 newArgv[newArgc] = ptr;
michael@0 361 newArgc++;
michael@0 362 continue;
michael@0 363 }
michael@0 364 ptr++;
michael@0 365 }
michael@0 366 if (ptr == newArgv[newArgc-1])
michael@0 367 newArgc--;
michael@0 368
michael@0 369 // attach browser stdout to metrotestharness stdout
michael@0 370 AttachToTestHarness();
michael@0 371
michael@0 372 int result = XRE_main(newArgc, newArgv, appData, mainFlags);
michael@0 373 XRE_FreeAppData(appData);
michael@0 374 return result;
michael@0 375 }
michael@0 376 }
michael@0 377 #endif
michael@0 378
michael@0 379 int result = XRE_main(argc, argv, appData, mainFlags);
michael@0 380 XRE_FreeAppData(appData);
michael@0 381 return result;
michael@0 382 #endif
michael@0 383
michael@0 384 NS_NOTREACHED("browser do_main failed to pickup proper initialization");
michael@0 385 return 255;
michael@0 386 }
michael@0 387
michael@0 388 #ifdef XP_WIN
michael@0 389
michael@0 390 /**
michael@0 391 * Used only when GetTickCount64 is not available on the platform.
michael@0 392 * Last result of GetTickCount call. Kept in [ms].
michael@0 393 */
michael@0 394 static DWORD sLastGTCResult = 0;
michael@0 395
michael@0 396 /**
michael@0 397 * Higher part of the 64-bit value of MozGetTickCount64,
michael@0 398 * incremented atomically.
michael@0 399 */
michael@0 400 static DWORD sLastGTCRollover = 0;
michael@0 401
michael@0 402 /**
michael@0 403 * Function protecting GetTickCount result from rolling over. The original
michael@0 404 * code comes from the Windows implementation of the TimeStamp class minus the
michael@0 405 * locking harness which isn't needed here.
michael@0 406 *
michael@0 407 * @returns The current time in milliseconds
michael@0 408 */
michael@0 409 static ULONGLONG WINAPI
michael@0 410 MozGetTickCount64()
michael@0 411 {
michael@0 412 DWORD GTC = ::GetTickCount();
michael@0 413
michael@0 414 /* Pull the rollover counter forward only if new value of GTC goes way
michael@0 415 * down under the last saved result */
michael@0 416 if ((sLastGTCResult > GTC) && ((sLastGTCResult - GTC) > (1UL << 30)))
michael@0 417 ++sLastGTCRollover;
michael@0 418
michael@0 419 sLastGTCResult = GTC;
michael@0 420 return (ULONGLONG)sLastGTCRollover << 32 | sLastGTCResult;
michael@0 421 }
michael@0 422
michael@0 423 typedef ULONGLONG (WINAPI* GetTickCount64_t)();
michael@0 424 static GetTickCount64_t sGetTickCount64 = nullptr;
michael@0 425
michael@0 426 #endif
michael@0 427
michael@0 428 /**
michael@0 429 * Local TimeStamp::Now()-compatible implementation used to record timestamps
michael@0 430 * which will be passed to XRE_StartupTimelineRecord().
michael@0 431 */
michael@0 432 static uint64_t
michael@0 433 TimeStamp_Now()
michael@0 434 {
michael@0 435 #ifdef XP_WIN
michael@0 436 LARGE_INTEGER freq;
michael@0 437 ::QueryPerformanceFrequency(&freq);
michael@0 438
michael@0 439 HMODULE kernelDLL = GetModuleHandleW(L"kernel32.dll");
michael@0 440 sGetTickCount64 = reinterpret_cast<GetTickCount64_t>
michael@0 441 (GetProcAddress(kernelDLL, "GetTickCount64"));
michael@0 442
michael@0 443 if (!sGetTickCount64) {
michael@0 444 /* If the platform does not support the GetTickCount64 (Windows XP doesn't),
michael@0 445 * then use our fallback implementation based on GetTickCount. */
michael@0 446 sGetTickCount64 = MozGetTickCount64;
michael@0 447 }
michael@0 448
michael@0 449 return sGetTickCount64() * freq.QuadPart;
michael@0 450 #elif defined(XP_MACOSX)
michael@0 451 return mach_absolute_time();
michael@0 452 #elif defined(HAVE_CLOCK_MONOTONIC)
michael@0 453 struct timespec ts;
michael@0 454 int rv = clock_gettime(CLOCK_MONOTONIC, &ts);
michael@0 455
michael@0 456 if (rv != 0) {
michael@0 457 return 0;
michael@0 458 }
michael@0 459
michael@0 460 uint64_t baseNs = (uint64_t)ts.tv_sec * 1000000000;
michael@0 461 return baseNs + (uint64_t)ts.tv_nsec;
michael@0 462 #endif
michael@0 463 }
michael@0 464
michael@0 465 static bool
michael@0 466 FileExists(const char *path)
michael@0 467 {
michael@0 468 #ifdef XP_WIN
michael@0 469 wchar_t wideDir[MAX_PATH];
michael@0 470 MultiByteToWideChar(CP_UTF8, 0, path, -1, wideDir, MAX_PATH);
michael@0 471 DWORD fileAttrs = GetFileAttributesW(wideDir);
michael@0 472 return fileAttrs != INVALID_FILE_ATTRIBUTES;
michael@0 473 #else
michael@0 474 return access(path, R_OK) == 0;
michael@0 475 #endif
michael@0 476 }
michael@0 477
michael@0 478 #ifdef LIBXUL_SDK
michael@0 479 # define XPCOM_PATH "xulrunner" XPCOM_FILE_PATH_SEPARATOR XPCOM_DLL
michael@0 480 #else
michael@0 481 # define XPCOM_PATH XPCOM_DLL
michael@0 482 #endif
michael@0 483 static nsresult
michael@0 484 InitXPCOMGlue(const char *argv0, nsIFile **xreDirectory)
michael@0 485 {
michael@0 486 char exePath[MAXPATHLEN];
michael@0 487
michael@0 488 nsresult rv = mozilla::BinaryPath::Get(argv0, exePath);
michael@0 489 if (NS_FAILED(rv)) {
michael@0 490 Output("Couldn't find the application directory.\n");
michael@0 491 return rv;
michael@0 492 }
michael@0 493
michael@0 494 char *lastSlash = strrchr(exePath, XPCOM_FILE_PATH_SEPARATOR[0]);
michael@0 495 if (!lastSlash || (size_t(lastSlash - exePath) > MAXPATHLEN - sizeof(XPCOM_PATH) - 1))
michael@0 496 return NS_ERROR_FAILURE;
michael@0 497
michael@0 498 strcpy(lastSlash + 1, XPCOM_PATH);
michael@0 499 lastSlash += sizeof(XPCOM_PATH) - sizeof(XPCOM_DLL);
michael@0 500
michael@0 501 if (!FileExists(exePath)) {
michael@0 502 #if defined(LIBXUL_SDK) && defined(XP_MACOSX)
michael@0 503 // Check for <bundle>/Contents/Frameworks/XUL.framework/libxpcom.dylib
michael@0 504 bool greFound = false;
michael@0 505 CFBundleRef appBundle = CFBundleGetMainBundle();
michael@0 506 if (!appBundle)
michael@0 507 return NS_ERROR_FAILURE;
michael@0 508 CFURLRef fwurl = CFBundleCopyPrivateFrameworksURL(appBundle);
michael@0 509 CFURLRef absfwurl = nullptr;
michael@0 510 if (fwurl) {
michael@0 511 absfwurl = CFURLCopyAbsoluteURL(fwurl);
michael@0 512 CFRelease(fwurl);
michael@0 513 }
michael@0 514 if (absfwurl) {
michael@0 515 CFURLRef xulurl =
michael@0 516 CFURLCreateCopyAppendingPathComponent(nullptr, absfwurl,
michael@0 517 CFSTR("XUL.framework"),
michael@0 518 true);
michael@0 519
michael@0 520 if (xulurl) {
michael@0 521 CFURLRef xpcomurl =
michael@0 522 CFURLCreateCopyAppendingPathComponent(nullptr, xulurl,
michael@0 523 CFSTR("libxpcom.dylib"),
michael@0 524 false);
michael@0 525
michael@0 526 if (xpcomurl) {
michael@0 527 if (CFURLGetFileSystemRepresentation(xpcomurl, true,
michael@0 528 (UInt8*) exePath,
michael@0 529 sizeof(exePath)) &&
michael@0 530 access(tbuffer, R_OK | X_OK) == 0) {
michael@0 531 if (realpath(tbuffer, exePath)) {
michael@0 532 greFound = true;
michael@0 533 }
michael@0 534 }
michael@0 535 CFRelease(xpcomurl);
michael@0 536 }
michael@0 537 CFRelease(xulurl);
michael@0 538 }
michael@0 539 CFRelease(absfwurl);
michael@0 540 }
michael@0 541 }
michael@0 542 if (!greFound) {
michael@0 543 #endif
michael@0 544 Output("Could not find the Mozilla runtime.\n");
michael@0 545 return NS_ERROR_FAILURE;
michael@0 546 }
michael@0 547
michael@0 548 // We do this because of data in bug 771745
michael@0 549 XPCOMGlueEnablePreload();
michael@0 550
michael@0 551 rv = XPCOMGlueStartup(exePath);
michael@0 552 if (NS_FAILED(rv)) {
michael@0 553 Output("Couldn't load XPCOM.\n");
michael@0 554 return rv;
michael@0 555 }
michael@0 556
michael@0 557 rv = XPCOMGlueLoadXULFunctions(kXULFuncs);
michael@0 558 if (NS_FAILED(rv)) {
michael@0 559 Output("Couldn't load XRE functions.\n");
michael@0 560 return rv;
michael@0 561 }
michael@0 562
michael@0 563 NS_LogInit();
michael@0 564
michael@0 565 // chop XPCOM_DLL off exePath
michael@0 566 *lastSlash = '\0';
michael@0 567 #ifdef XP_WIN
michael@0 568 rv = NS_NewLocalFile(NS_ConvertUTF8toUTF16(exePath), false,
michael@0 569 xreDirectory);
michael@0 570 #else
michael@0 571 rv = NS_NewNativeLocalFile(nsDependentCString(exePath), false,
michael@0 572 xreDirectory);
michael@0 573 #endif
michael@0 574
michael@0 575 return rv;
michael@0 576 }
michael@0 577
michael@0 578 int main(int argc, char* argv[])
michael@0 579 {
michael@0 580 #ifdef DEBUG_delay_start_metro
michael@0 581 Sleep(5000);
michael@0 582 #endif
michael@0 583 uint64_t start = TimeStamp_Now();
michael@0 584
michael@0 585 #ifdef XP_MACOSX
michael@0 586 TriggerQuirks();
michael@0 587 #endif
michael@0 588
michael@0 589 int gotCounters;
michael@0 590 #if defined(XP_UNIX)
michael@0 591 struct rusage initialRUsage;
michael@0 592 gotCounters = !getrusage(RUSAGE_SELF, &initialRUsage);
michael@0 593 #elif defined(XP_WIN)
michael@0 594 IO_COUNTERS ioCounters;
michael@0 595 gotCounters = GetProcessIoCounters(GetCurrentProcess(), &ioCounters);
michael@0 596 #endif
michael@0 597
michael@0 598 nsIFile *xreDirectory;
michael@0 599
michael@0 600 #ifdef HAS_DLL_BLOCKLIST
michael@0 601 DllBlocklist_Initialize();
michael@0 602
michael@0 603 #ifdef DEBUG
michael@0 604 // In order to be effective against AppInit DLLs, the blocklist must be
michael@0 605 // initialized before user32.dll is loaded into the process (bug 932100).
michael@0 606 if (GetModuleHandleA("user32.dll")) {
michael@0 607 fprintf(stderr, "DLL blocklist was unable to intercept AppInit DLLs.\n");
michael@0 608 }
michael@0 609 #endif
michael@0 610 #endif
michael@0 611
michael@0 612 nsresult rv = InitXPCOMGlue(argv[0], &xreDirectory);
michael@0 613 if (NS_FAILED(rv)) {
michael@0 614 return 255;
michael@0 615 }
michael@0 616
michael@0 617 XRE_StartupTimelineRecord(mozilla::StartupTimeline::START, start);
michael@0 618
michael@0 619 if (gotCounters) {
michael@0 620 #if defined(XP_WIN)
michael@0 621 XRE_TelemetryAccumulate(mozilla::Telemetry::EARLY_GLUESTARTUP_READ_OPS,
michael@0 622 int(ioCounters.ReadOperationCount));
michael@0 623 XRE_TelemetryAccumulate(mozilla::Telemetry::EARLY_GLUESTARTUP_READ_TRANSFER,
michael@0 624 int(ioCounters.ReadTransferCount / 1024));
michael@0 625 IO_COUNTERS newIoCounters;
michael@0 626 if (GetProcessIoCounters(GetCurrentProcess(), &newIoCounters)) {
michael@0 627 XRE_TelemetryAccumulate(mozilla::Telemetry::GLUESTARTUP_READ_OPS,
michael@0 628 int(newIoCounters.ReadOperationCount - ioCounters.ReadOperationCount));
michael@0 629 XRE_TelemetryAccumulate(mozilla::Telemetry::GLUESTARTUP_READ_TRANSFER,
michael@0 630 int((newIoCounters.ReadTransferCount - ioCounters.ReadTransferCount) / 1024));
michael@0 631 }
michael@0 632 #elif defined(XP_UNIX)
michael@0 633 XRE_TelemetryAccumulate(mozilla::Telemetry::EARLY_GLUESTARTUP_HARD_FAULTS,
michael@0 634 int(initialRUsage.ru_majflt));
michael@0 635 struct rusage newRUsage;
michael@0 636 if (!getrusage(RUSAGE_SELF, &newRUsage)) {
michael@0 637 XRE_TelemetryAccumulate(mozilla::Telemetry::GLUESTARTUP_HARD_FAULTS,
michael@0 638 int(newRUsage.ru_majflt - initialRUsage.ru_majflt));
michael@0 639 }
michael@0 640 #endif
michael@0 641 }
michael@0 642
michael@0 643 int result = do_main(argc, argv, xreDirectory);
michael@0 644
michael@0 645 NS_LogTerm();
michael@0 646
michael@0 647 #ifdef XP_MACOSX
michael@0 648 // Allow writes again. While we would like to catch writes from static
michael@0 649 // destructors to allow early exits to use _exit, we know that there is
michael@0 650 // at least one such write that we don't control (see bug 826029). For
michael@0 651 // now we enable writes again and early exits will have to use exit instead
michael@0 652 // of _exit.
michael@0 653 XRE_StopLateWriteChecks();
michael@0 654 #endif
michael@0 655
michael@0 656 return result;
michael@0 657 }

mercurial