browser/app/nsBrowserApp.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/browser/app/nsBrowserApp.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,657 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#include "nsXULAppAPI.h"
    1.10 +#include "mozilla/AppData.h"
    1.11 +#include "application.ini.h"
    1.12 +#include "nsXPCOMGlue.h"
    1.13 +#if defined(XP_WIN)
    1.14 +#include <windows.h>
    1.15 +#include <stdlib.h>
    1.16 +#include <io.h>
    1.17 +#include <fcntl.h>
    1.18 +#elif defined(XP_UNIX)
    1.19 +#include <sys/resource.h>
    1.20 +#include <time.h>
    1.21 +#include <unistd.h>
    1.22 +#endif
    1.23 +
    1.24 +#ifdef XP_MACOSX
    1.25 +#include <mach/mach_time.h>
    1.26 +#include "MacQuirks.h"
    1.27 +#endif
    1.28 +
    1.29 +#include <stdio.h>
    1.30 +#include <stdarg.h>
    1.31 +#include <time.h>
    1.32 +
    1.33 +#include "nsCOMPtr.h"
    1.34 +#include "nsIFile.h"
    1.35 +#include "nsStringGlue.h"
    1.36 +
    1.37 +// Easy access to a five second startup delay used to get
    1.38 +// a debugger attached in the metro environment. 
    1.39 +// #define DEBUG_delay_start_metro
    1.40 +
    1.41 +#ifdef XP_WIN
    1.42 +// we want a wmain entry point
    1.43 +#include "nsWindowsWMain.cpp"
    1.44 +#define snprintf _snprintf
    1.45 +#define strcasecmp _stricmp
    1.46 +#endif
    1.47 +#include "BinaryPath.h"
    1.48 +
    1.49 +#include "nsXPCOMPrivate.h" // for MAXPATHLEN and XPCOM_DLL
    1.50 +
    1.51 +#include "mozilla/Telemetry.h"
    1.52 +#include "mozilla/WindowsDllBlocklist.h"
    1.53 +
    1.54 +using namespace mozilla;
    1.55 +
    1.56 +#define kDesktopFolder "browser"
    1.57 +#define kMetroFolder "metro"
    1.58 +#define kMetroAppIniFilename "metroapp.ini"
    1.59 +#ifdef XP_WIN
    1.60 +#define kMetroTestFile "tests.ini"
    1.61 +const char* kMetroConsoleIdParam = "testconsoleid=";
    1.62 +#endif
    1.63 +
    1.64 +static void Output(const char *fmt, ... )
    1.65 +{
    1.66 +  va_list ap;
    1.67 +  va_start(ap, fmt);
    1.68 +
    1.69 +#ifndef XP_WIN
    1.70 +  vfprintf(stderr, fmt, ap);
    1.71 +#else
    1.72 +  char msg[2048];
    1.73 +  vsnprintf_s(msg, _countof(msg), _TRUNCATE, fmt, ap);
    1.74 +
    1.75 +  wchar_t wide_msg[2048];
    1.76 +  MultiByteToWideChar(CP_UTF8,
    1.77 +                      0,
    1.78 +                      msg,
    1.79 +                      -1,
    1.80 +                      wide_msg,
    1.81 +                      _countof(wide_msg));
    1.82 +#if MOZ_WINCONSOLE
    1.83 +  fwprintf_s(stderr, wide_msg);
    1.84 +#else
    1.85 +  // Linking user32 at load-time interferes with the DLL blocklist (bug 932100).
    1.86 +  // This is a rare codepath, so we can load user32 at run-time instead.
    1.87 +  HMODULE user32 = LoadLibraryW(L"user32.dll");
    1.88 +  if (user32) {
    1.89 +    decltype(MessageBoxW)* messageBoxW =
    1.90 +      (decltype(MessageBoxW)*) GetProcAddress(user32, "MessageBoxW");
    1.91 +    if (messageBoxW) {
    1.92 +      messageBoxW(nullptr, wide_msg, L"Firefox", MB_OK
    1.93 +                                               | MB_ICONERROR
    1.94 +                                               | MB_SETFOREGROUND);
    1.95 +    }
    1.96 +    FreeLibrary(user32);
    1.97 +  }
    1.98 +#endif
    1.99 +#endif
   1.100 +
   1.101 +  va_end(ap);
   1.102 +}
   1.103 +
   1.104 +/**
   1.105 + * Return true if |arg| matches the given argument name.
   1.106 + */
   1.107 +static bool IsArg(const char* arg, const char* s)
   1.108 +{
   1.109 +  if (*arg == '-')
   1.110 +  {
   1.111 +    if (*++arg == '-')
   1.112 +      ++arg;
   1.113 +    return !strcasecmp(arg, s);
   1.114 +  }
   1.115 +
   1.116 +#if defined(XP_WIN)
   1.117 +  if (*arg == '/')
   1.118 +    return !strcasecmp(++arg, s);
   1.119 +#endif
   1.120 +
   1.121 +  return false;
   1.122 +}
   1.123 +
   1.124 +#ifdef XP_WIN
   1.125 +/*
   1.126 + * AttachToTestHarness - Windows helper for when we are running
   1.127 + * in the immersive environment. Firefox is launched by Windows in
   1.128 + * response to a request by metrotestharness, which is launched by
   1.129 + * runtests.py. As such stdout in fx doesn't point to the right
   1.130 + * stream. This helper touches up stdout such that test output gets
   1.131 + * routed to a named pipe metrotestharness creates and dumps to its
   1.132 + * stdout.
   1.133 + */
   1.134 +static void AttachToTestHarness()
   1.135 +{
   1.136 +  // attach to the metrotestharness named logging pipe
   1.137 +  HANDLE winOut = CreateFileA("\\\\.\\pipe\\metrotestharness",
   1.138 +                              GENERIC_WRITE,
   1.139 +                              FILE_SHARE_WRITE, 0,
   1.140 +                              OPEN_EXISTING, 0, 0);
   1.141 +  
   1.142 +  if (winOut == INVALID_HANDLE_VALUE) {
   1.143 +    OutputDebugStringW(L"Could not create named logging pipe.\n");
   1.144 +    return;
   1.145 +  }
   1.146 +
   1.147 +  // Set the c runtime handle
   1.148 +  int stdOut = _open_osfhandle((intptr_t)winOut, _O_APPEND);
   1.149 +  if (stdOut == -1) {
   1.150 +    OutputDebugStringW(L"Could not open c-runtime handle.\n");
   1.151 +    return;
   1.152 +  }
   1.153 +  FILE *fp = _fdopen(stdOut, "a");
   1.154 +  *stdout = *fp;
   1.155 +}
   1.156 +#endif
   1.157 +
   1.158 +XRE_GetFileFromPathType XRE_GetFileFromPath;
   1.159 +XRE_CreateAppDataType XRE_CreateAppData;
   1.160 +XRE_FreeAppDataType XRE_FreeAppData;
   1.161 +XRE_TelemetryAccumulateType XRE_TelemetryAccumulate;
   1.162 +XRE_StartupTimelineRecordType XRE_StartupTimelineRecord;
   1.163 +XRE_mainType XRE_main;
   1.164 +XRE_StopLateWriteChecksType XRE_StopLateWriteChecks;
   1.165 +
   1.166 +static const nsDynamicFunctionLoad kXULFuncs[] = {
   1.167 +    { "XRE_GetFileFromPath", (NSFuncPtr*) &XRE_GetFileFromPath },
   1.168 +    { "XRE_CreateAppData", (NSFuncPtr*) &XRE_CreateAppData },
   1.169 +    { "XRE_FreeAppData", (NSFuncPtr*) &XRE_FreeAppData },
   1.170 +    { "XRE_TelemetryAccumulate", (NSFuncPtr*) &XRE_TelemetryAccumulate },
   1.171 +    { "XRE_StartupTimelineRecord", (NSFuncPtr*) &XRE_StartupTimelineRecord },
   1.172 +    { "XRE_main", (NSFuncPtr*) &XRE_main },
   1.173 +    { "XRE_StopLateWriteChecks", (NSFuncPtr*) &XRE_StopLateWriteChecks },
   1.174 +    { nullptr, nullptr }
   1.175 +};
   1.176 +
   1.177 +static int do_main(int argc, char* argv[], nsIFile *xreDirectory)
   1.178 +{
   1.179 +  nsCOMPtr<nsIFile> appini;
   1.180 +  nsresult rv;
   1.181 +  uint32_t mainFlags = 0;
   1.182 +
   1.183 +  // Allow firefox.exe to launch XULRunner apps via -app <application.ini>
   1.184 +  // Note that -app must be the *first* argument.
   1.185 +  const char *appDataFile = getenv("XUL_APP_FILE");
   1.186 +  if (appDataFile && *appDataFile) {
   1.187 +    rv = XRE_GetFileFromPath(appDataFile, getter_AddRefs(appini));
   1.188 +    if (NS_FAILED(rv)) {
   1.189 +      Output("Invalid path found: '%s'", appDataFile);
   1.190 +      return 255;
   1.191 +    }
   1.192 +  }
   1.193 +  else if (argc > 1 && IsArg(argv[1], "app")) {
   1.194 +    if (argc == 2) {
   1.195 +      Output("Incorrect number of arguments passed to -app");
   1.196 +      return 255;
   1.197 +    }
   1.198 +
   1.199 +    rv = XRE_GetFileFromPath(argv[2], getter_AddRefs(appini));
   1.200 +    if (NS_FAILED(rv)) {
   1.201 +      Output("application.ini path not recognized: '%s'", argv[2]);
   1.202 +      return 255;
   1.203 +    }
   1.204 +
   1.205 +    char appEnv[MAXPATHLEN];
   1.206 +    snprintf(appEnv, MAXPATHLEN, "XUL_APP_FILE=%s", argv[2]);
   1.207 +    if (putenv(appEnv)) {
   1.208 +      Output("Couldn't set %s.\n", appEnv);
   1.209 +      return 255;
   1.210 +    }
   1.211 +    argv[2] = argv[0];
   1.212 +    argv += 2;
   1.213 +    argc -= 2;
   1.214 +  }
   1.215 +
   1.216 +  if (appini) {
   1.217 +    nsXREAppData *appData;
   1.218 +    rv = XRE_CreateAppData(appini, &appData);
   1.219 +    if (NS_FAILED(rv)) {
   1.220 +      Output("Couldn't read application.ini");
   1.221 +      return 255;
   1.222 +    }
   1.223 +    // xreDirectory already has a refcount from NS_NewLocalFile
   1.224 +    appData->xreDirectory = xreDirectory;
   1.225 +    int result = XRE_main(argc, argv, appData, mainFlags);
   1.226 +    XRE_FreeAppData(appData);
   1.227 +    return result;
   1.228 +  }
   1.229 +
   1.230 +  bool metroOnDesktop = false;
   1.231 +
   1.232 +#ifdef MOZ_METRO
   1.233 +  if (argc > 1) {
   1.234 +    // This command-line flag is passed to our executable when it is to be
   1.235 +    // launched in metro mode (i.e. our EXE is registered as the default
   1.236 +    // browser and the user has tapped our EXE's tile)
   1.237 +    if (IsArg(argv[1], "ServerName:DefaultBrowserServer")) {
   1.238 +      mainFlags = XRE_MAIN_FLAG_USE_METRO;
   1.239 +      argv[1] = argv[0];
   1.240 +      argv++;
   1.241 +      argc--;
   1.242 +    } else if (IsArg(argv[1], "BackgroundSessionClosed")) {
   1.243 +      // This command line flag is used for indirect shutdowns, the OS
   1.244 +      // relaunches Metro Firefox with this command line arg.
   1.245 +      mainFlags = XRE_MAIN_FLAG_USE_METRO;
   1.246 +    } else {
   1.247 +#ifndef RELEASE_BUILD
   1.248 +      // This command-line flag is used to test the metro browser in a desktop
   1.249 +      // environment.
   1.250 +      for (int idx = 1; idx < argc; idx++) {
   1.251 +        if (IsArg(argv[idx], "metrodesktop")) {
   1.252 +          metroOnDesktop = true;
   1.253 +          // Disable crash reporting when running in metrodesktop mode.
   1.254 +          char crashSwitch[] = "MOZ_CRASHREPORTER_DISABLE=1";
   1.255 +          putenv(crashSwitch);
   1.256 +          break;
   1.257 +        } 
   1.258 +      }
   1.259 +#endif
   1.260 +    }
   1.261 +  }
   1.262 +#endif
   1.263 +
   1.264 +  // Desktop browser launch
   1.265 +  if (mainFlags != XRE_MAIN_FLAG_USE_METRO && !metroOnDesktop) {
   1.266 +    ScopedAppData appData(&sAppData);
   1.267 +    nsCOMPtr<nsIFile> exeFile;
   1.268 +    rv = mozilla::BinaryPath::GetFile(argv[0], getter_AddRefs(exeFile));
   1.269 +    if (NS_FAILED(rv)) {
   1.270 +      Output("Couldn't find the application directory.\n");
   1.271 +      return 255;
   1.272 +    }
   1.273 +
   1.274 +    nsCOMPtr<nsIFile> greDir;
   1.275 +    exeFile->GetParent(getter_AddRefs(greDir));
   1.276 +
   1.277 +    nsCOMPtr<nsIFile> appSubdir;
   1.278 +    greDir->Clone(getter_AddRefs(appSubdir));
   1.279 +    appSubdir->Append(NS_LITERAL_STRING(kDesktopFolder));
   1.280 +
   1.281 +    SetStrongPtr(appData.directory, static_cast<nsIFile*>(appSubdir.get()));
   1.282 +    // xreDirectory already has a refcount from NS_NewLocalFile
   1.283 +    appData.xreDirectory = xreDirectory;
   1.284 +
   1.285 +    return XRE_main(argc, argv, &appData, mainFlags);
   1.286 +  }
   1.287 +
   1.288 +  // Metro browser launch
   1.289 +#ifdef MOZ_METRO
   1.290 +  nsCOMPtr<nsIFile> iniFile, appSubdir;
   1.291 +
   1.292 +  xreDirectory->Clone(getter_AddRefs(iniFile));
   1.293 +  xreDirectory->Clone(getter_AddRefs(appSubdir));
   1.294 +
   1.295 +  iniFile->Append(NS_LITERAL_STRING(kMetroFolder));
   1.296 +  iniFile->Append(NS_LITERAL_STRING(kMetroAppIniFilename));
   1.297 +
   1.298 +  appSubdir->Append(NS_LITERAL_STRING(kMetroFolder));
   1.299 +
   1.300 +  nsAutoCString path;
   1.301 +  if (NS_FAILED(iniFile->GetNativePath(path))) {
   1.302 +    Output("Couldn't get ini file path.\n");
   1.303 +    return 255;
   1.304 +  }
   1.305 +
   1.306 +  nsXREAppData *appData;
   1.307 +  rv = XRE_CreateAppData(iniFile, &appData);
   1.308 +  if (NS_FAILED(rv) || !appData) {
   1.309 +    Output("Couldn't read application.ini");
   1.310 +    return 255;
   1.311 +  }
   1.312 +
   1.313 +  SetStrongPtr(appData->directory, static_cast<nsIFile*>(appSubdir.get()));
   1.314 +  // xreDirectory already has a refcount from NS_NewLocalFile
   1.315 +  appData->xreDirectory = xreDirectory;
   1.316 +
   1.317 +#ifdef XP_WIN
   1.318 +  if (!metroOnDesktop) {
   1.319 +    nsCOMPtr<nsIFile> testFile;
   1.320 +
   1.321 +    xreDirectory->Clone(getter_AddRefs(testFile));
   1.322 +    testFile->Append(NS_LITERAL_STRING(kMetroTestFile));
   1.323 +
   1.324 +    nsAutoCString path;
   1.325 +    if (NS_FAILED(testFile->GetNativePath(path))) {
   1.326 +      Output("Couldn't get test file path.\n");
   1.327 +      return 255;
   1.328 +    }
   1.329 +
   1.330 +    // Check for a metro test harness command line args file
   1.331 +    HANDLE hTestFile = CreateFileA(path.get(),
   1.332 +                                   GENERIC_READ,
   1.333 +                                   0, nullptr, OPEN_EXISTING,
   1.334 +                                   FILE_ATTRIBUTE_NORMAL,
   1.335 +                                   nullptr);
   1.336 +    if (hTestFile != INVALID_HANDLE_VALUE) {
   1.337 +      // Typical test harness command line args string is around 100 bytes.
   1.338 +      char buffer[1024];
   1.339 +      memset(buffer, 0, sizeof(buffer));
   1.340 +      DWORD bytesRead = 0;
   1.341 +      if (!ReadFile(hTestFile, (VOID*)buffer, sizeof(buffer)-1,
   1.342 +                    &bytesRead, nullptr) || !bytesRead) {
   1.343 +        CloseHandle(hTestFile);
   1.344 +        printf("failed to read test file '%s'", testFile);
   1.345 +        return -1;
   1.346 +      }
   1.347 +      CloseHandle(hTestFile);
   1.348 +
   1.349 +      // Build new args array
   1.350 +      char* newArgv[20];
   1.351 +      int newArgc = 1;
   1.352 +
   1.353 +      memset(newArgv, 0, sizeof(newArgv));
   1.354 +
   1.355 +      char* ptr = buffer;
   1.356 +      newArgv[0] = ptr;
   1.357 +      while (*ptr != '\0' &&
   1.358 +             (ptr - buffer) < sizeof(buffer) &&
   1.359 +             newArgc < ARRAYSIZE(newArgv)) {
   1.360 +        if (isspace(*ptr)) {
   1.361 +          *ptr = '\0';
   1.362 +          ptr++;
   1.363 +          newArgv[newArgc] = ptr;
   1.364 +          newArgc++;
   1.365 +          continue;
   1.366 +        }
   1.367 +        ptr++;
   1.368 +      }
   1.369 +      if (ptr == newArgv[newArgc-1])
   1.370 +        newArgc--;
   1.371 +
   1.372 +      // attach browser stdout to metrotestharness stdout
   1.373 +      AttachToTestHarness();
   1.374 +
   1.375 +      int result = XRE_main(newArgc, newArgv, appData, mainFlags);
   1.376 +      XRE_FreeAppData(appData);
   1.377 +      return result;
   1.378 +    }
   1.379 +  }
   1.380 +#endif
   1.381 +
   1.382 +  int result = XRE_main(argc, argv, appData, mainFlags);
   1.383 +  XRE_FreeAppData(appData);
   1.384 +  return result;
   1.385 +#endif
   1.386 +
   1.387 +  NS_NOTREACHED("browser do_main failed to pickup proper initialization");
   1.388 +  return 255;
   1.389 +}
   1.390 +
   1.391 +#ifdef XP_WIN
   1.392 +
   1.393 +/**
   1.394 + * Used only when GetTickCount64 is not available on the platform.
   1.395 + * Last result of GetTickCount call. Kept in [ms].
   1.396 + */
   1.397 +static DWORD sLastGTCResult = 0;
   1.398 +
   1.399 +/**
   1.400 + *  Higher part of the 64-bit value of MozGetTickCount64,
   1.401 + * incremented atomically.
   1.402 + */
   1.403 +static DWORD sLastGTCRollover = 0;
   1.404 +
   1.405 +/**
   1.406 + * Function protecting GetTickCount result from rolling over. The original
   1.407 + * code comes from the Windows implementation of the TimeStamp class minus the
   1.408 + * locking harness which isn't needed here.
   1.409 + *
   1.410 + * @returns The current time in milliseconds
   1.411 + */
   1.412 +static ULONGLONG WINAPI
   1.413 +MozGetTickCount64()
   1.414 +{
   1.415 +  DWORD GTC = ::GetTickCount();
   1.416 +
   1.417 +  /* Pull the rollover counter forward only if new value of GTC goes way
   1.418 +   * down under the last saved result */
   1.419 +  if ((sLastGTCResult > GTC) && ((sLastGTCResult - GTC) > (1UL << 30)))
   1.420 +    ++sLastGTCRollover;
   1.421 +
   1.422 +  sLastGTCResult = GTC;
   1.423 +  return (ULONGLONG)sLastGTCRollover << 32 | sLastGTCResult;
   1.424 +}
   1.425 +
   1.426 +typedef ULONGLONG (WINAPI* GetTickCount64_t)();
   1.427 +static GetTickCount64_t sGetTickCount64 = nullptr;
   1.428 +
   1.429 +#endif
   1.430 +
   1.431 +/**
   1.432 + * Local TimeStamp::Now()-compatible implementation used to record timestamps
   1.433 + * which will be passed to XRE_StartupTimelineRecord().
   1.434 + */
   1.435 +static uint64_t
   1.436 +TimeStamp_Now()
   1.437 +{
   1.438 +#ifdef XP_WIN
   1.439 +  LARGE_INTEGER freq;
   1.440 +  ::QueryPerformanceFrequency(&freq);
   1.441 +
   1.442 +  HMODULE kernelDLL = GetModuleHandleW(L"kernel32.dll");
   1.443 +  sGetTickCount64 = reinterpret_cast<GetTickCount64_t>
   1.444 +    (GetProcAddress(kernelDLL, "GetTickCount64"));
   1.445 +
   1.446 +  if (!sGetTickCount64) {
   1.447 +    /* If the platform does not support the GetTickCount64 (Windows XP doesn't),
   1.448 +     * then use our fallback implementation based on GetTickCount. */
   1.449 +    sGetTickCount64 = MozGetTickCount64;
   1.450 +  }
   1.451 +
   1.452 +  return sGetTickCount64() * freq.QuadPart;
   1.453 +#elif defined(XP_MACOSX)
   1.454 +  return mach_absolute_time();
   1.455 +#elif defined(HAVE_CLOCK_MONOTONIC)
   1.456 +  struct timespec ts;
   1.457 +  int rv = clock_gettime(CLOCK_MONOTONIC, &ts);
   1.458 +
   1.459 +  if (rv != 0) {
   1.460 +    return 0;
   1.461 +  }
   1.462 +
   1.463 +  uint64_t baseNs = (uint64_t)ts.tv_sec * 1000000000;
   1.464 +  return baseNs + (uint64_t)ts.tv_nsec;
   1.465 +#endif
   1.466 +}
   1.467 +
   1.468 +static bool
   1.469 +FileExists(const char *path)
   1.470 +{
   1.471 +#ifdef XP_WIN
   1.472 +  wchar_t wideDir[MAX_PATH];
   1.473 +  MultiByteToWideChar(CP_UTF8, 0, path, -1, wideDir, MAX_PATH);
   1.474 +  DWORD fileAttrs = GetFileAttributesW(wideDir);
   1.475 +  return fileAttrs != INVALID_FILE_ATTRIBUTES;
   1.476 +#else
   1.477 +  return access(path, R_OK) == 0;
   1.478 +#endif
   1.479 +}
   1.480 +
   1.481 +#ifdef LIBXUL_SDK
   1.482 +#  define XPCOM_PATH "xulrunner" XPCOM_FILE_PATH_SEPARATOR XPCOM_DLL
   1.483 +#else
   1.484 +#  define XPCOM_PATH XPCOM_DLL
   1.485 +#endif
   1.486 +static nsresult
   1.487 +InitXPCOMGlue(const char *argv0, nsIFile **xreDirectory)
   1.488 +{
   1.489 +  char exePath[MAXPATHLEN];
   1.490 +
   1.491 +  nsresult rv = mozilla::BinaryPath::Get(argv0, exePath);
   1.492 +  if (NS_FAILED(rv)) {
   1.493 +    Output("Couldn't find the application directory.\n");
   1.494 +    return rv;
   1.495 +  }
   1.496 +
   1.497 +  char *lastSlash = strrchr(exePath, XPCOM_FILE_PATH_SEPARATOR[0]);
   1.498 +  if (!lastSlash || (size_t(lastSlash - exePath) > MAXPATHLEN - sizeof(XPCOM_PATH) - 1))
   1.499 +    return NS_ERROR_FAILURE;
   1.500 +
   1.501 +  strcpy(lastSlash + 1, XPCOM_PATH);
   1.502 +  lastSlash += sizeof(XPCOM_PATH) - sizeof(XPCOM_DLL);
   1.503 +
   1.504 +  if (!FileExists(exePath)) {
   1.505 +#if defined(LIBXUL_SDK) && defined(XP_MACOSX)
   1.506 +    // Check for <bundle>/Contents/Frameworks/XUL.framework/libxpcom.dylib
   1.507 +    bool greFound = false;
   1.508 +    CFBundleRef appBundle = CFBundleGetMainBundle();
   1.509 +    if (!appBundle)
   1.510 +      return NS_ERROR_FAILURE;
   1.511 +    CFURLRef fwurl = CFBundleCopyPrivateFrameworksURL(appBundle);
   1.512 +    CFURLRef absfwurl = nullptr;
   1.513 +    if (fwurl) {
   1.514 +      absfwurl = CFURLCopyAbsoluteURL(fwurl);
   1.515 +      CFRelease(fwurl);
   1.516 +    }
   1.517 +    if (absfwurl) {
   1.518 +      CFURLRef xulurl =
   1.519 +        CFURLCreateCopyAppendingPathComponent(nullptr, absfwurl,
   1.520 +                                              CFSTR("XUL.framework"),
   1.521 +                                              true);
   1.522 +
   1.523 +      if (xulurl) {
   1.524 +        CFURLRef xpcomurl =
   1.525 +          CFURLCreateCopyAppendingPathComponent(nullptr, xulurl,
   1.526 +                                                CFSTR("libxpcom.dylib"),
   1.527 +                                                false);
   1.528 +
   1.529 +        if (xpcomurl) {
   1.530 +          if (CFURLGetFileSystemRepresentation(xpcomurl, true,
   1.531 +                                               (UInt8*) exePath,
   1.532 +                                               sizeof(exePath)) &&
   1.533 +              access(tbuffer, R_OK | X_OK) == 0) {
   1.534 +            if (realpath(tbuffer, exePath)) {
   1.535 +              greFound = true;
   1.536 +            }
   1.537 +          }
   1.538 +          CFRelease(xpcomurl);
   1.539 +        }
   1.540 +        CFRelease(xulurl);
   1.541 +      }
   1.542 +      CFRelease(absfwurl);
   1.543 +    }
   1.544 +  }
   1.545 +  if (!greFound) {
   1.546 +#endif
   1.547 +    Output("Could not find the Mozilla runtime.\n");
   1.548 +    return NS_ERROR_FAILURE;
   1.549 +  }
   1.550 +
   1.551 +  // We do this because of data in bug 771745
   1.552 +  XPCOMGlueEnablePreload();
   1.553 +
   1.554 +  rv = XPCOMGlueStartup(exePath);
   1.555 +  if (NS_FAILED(rv)) {
   1.556 +    Output("Couldn't load XPCOM.\n");
   1.557 +    return rv;
   1.558 +  }
   1.559 +
   1.560 +  rv = XPCOMGlueLoadXULFunctions(kXULFuncs);
   1.561 +  if (NS_FAILED(rv)) {
   1.562 +    Output("Couldn't load XRE functions.\n");
   1.563 +    return rv;
   1.564 +  }
   1.565 +
   1.566 +  NS_LogInit();
   1.567 +
   1.568 +  // chop XPCOM_DLL off exePath
   1.569 +  *lastSlash = '\0';
   1.570 +#ifdef XP_WIN
   1.571 +  rv = NS_NewLocalFile(NS_ConvertUTF8toUTF16(exePath), false,
   1.572 +                       xreDirectory);
   1.573 +#else
   1.574 +  rv = NS_NewNativeLocalFile(nsDependentCString(exePath), false,
   1.575 +                             xreDirectory);
   1.576 +#endif
   1.577 +
   1.578 +  return rv;
   1.579 +}
   1.580 +
   1.581 +int main(int argc, char* argv[])
   1.582 +{
   1.583 +#ifdef DEBUG_delay_start_metro
   1.584 +  Sleep(5000);
   1.585 +#endif
   1.586 +  uint64_t start = TimeStamp_Now();
   1.587 +
   1.588 +#ifdef XP_MACOSX
   1.589 +  TriggerQuirks();
   1.590 +#endif
   1.591 +
   1.592 +  int gotCounters;
   1.593 +#if defined(XP_UNIX)
   1.594 +  struct rusage initialRUsage;
   1.595 +  gotCounters = !getrusage(RUSAGE_SELF, &initialRUsage);
   1.596 +#elif defined(XP_WIN)
   1.597 +  IO_COUNTERS ioCounters;
   1.598 +  gotCounters = GetProcessIoCounters(GetCurrentProcess(), &ioCounters);
   1.599 +#endif
   1.600 +
   1.601 +  nsIFile *xreDirectory;
   1.602 +
   1.603 +#ifdef HAS_DLL_BLOCKLIST
   1.604 +  DllBlocklist_Initialize();
   1.605 +
   1.606 +#ifdef DEBUG
   1.607 +  // In order to be effective against AppInit DLLs, the blocklist must be
   1.608 +  // initialized before user32.dll is loaded into the process (bug 932100).
   1.609 +  if (GetModuleHandleA("user32.dll")) {
   1.610 +    fprintf(stderr, "DLL blocklist was unable to intercept AppInit DLLs.\n");
   1.611 +  }
   1.612 +#endif
   1.613 +#endif
   1.614 +
   1.615 +  nsresult rv = InitXPCOMGlue(argv[0], &xreDirectory);
   1.616 +  if (NS_FAILED(rv)) {
   1.617 +    return 255;
   1.618 +  }
   1.619 +
   1.620 +  XRE_StartupTimelineRecord(mozilla::StartupTimeline::START, start);
   1.621 +
   1.622 +  if (gotCounters) {
   1.623 +#if defined(XP_WIN)
   1.624 +    XRE_TelemetryAccumulate(mozilla::Telemetry::EARLY_GLUESTARTUP_READ_OPS,
   1.625 +                            int(ioCounters.ReadOperationCount));
   1.626 +    XRE_TelemetryAccumulate(mozilla::Telemetry::EARLY_GLUESTARTUP_READ_TRANSFER,
   1.627 +                            int(ioCounters.ReadTransferCount / 1024));
   1.628 +    IO_COUNTERS newIoCounters;
   1.629 +    if (GetProcessIoCounters(GetCurrentProcess(), &newIoCounters)) {
   1.630 +      XRE_TelemetryAccumulate(mozilla::Telemetry::GLUESTARTUP_READ_OPS,
   1.631 +                              int(newIoCounters.ReadOperationCount - ioCounters.ReadOperationCount));
   1.632 +      XRE_TelemetryAccumulate(mozilla::Telemetry::GLUESTARTUP_READ_TRANSFER,
   1.633 +                              int((newIoCounters.ReadTransferCount - ioCounters.ReadTransferCount) / 1024));
   1.634 +    }
   1.635 +#elif defined(XP_UNIX)
   1.636 +    XRE_TelemetryAccumulate(mozilla::Telemetry::EARLY_GLUESTARTUP_HARD_FAULTS,
   1.637 +                            int(initialRUsage.ru_majflt));
   1.638 +    struct rusage newRUsage;
   1.639 +    if (!getrusage(RUSAGE_SELF, &newRUsage)) {
   1.640 +      XRE_TelemetryAccumulate(mozilla::Telemetry::GLUESTARTUP_HARD_FAULTS,
   1.641 +                              int(newRUsage.ru_majflt - initialRUsage.ru_majflt));
   1.642 +    }
   1.643 +#endif
   1.644 +  }
   1.645 +
   1.646 +  int result = do_main(argc, argv, xreDirectory);
   1.647 +
   1.648 +  NS_LogTerm();
   1.649 +
   1.650 +#ifdef XP_MACOSX
   1.651 +  // Allow writes again. While we would like to catch writes from static
   1.652 +  // destructors to allow early exits to use _exit, we know that there is
   1.653 +  // at least one such write that we don't control (see bug 826029). For
   1.654 +  // now we enable writes again and early exits will have to use exit instead
   1.655 +  // of _exit.
   1.656 +  XRE_StopLateWriteChecks();
   1.657 +#endif
   1.658 +
   1.659 +  return result;
   1.660 +}

mercurial