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.

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

mercurial