michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "nsXULAppAPI.h" michael@0: #include "application.ini.h" michael@0: #include "nsXPCOMGlue.h" michael@0: #if defined(XP_WIN) michael@0: #include michael@0: #include michael@0: #elif defined(XP_UNIX) michael@0: #include michael@0: #include michael@0: #include michael@0: #endif michael@0: michael@0: #include michael@0: #include michael@0: michael@0: #include "nsCOMPtr.h" michael@0: #include "nsIFile.h" michael@0: #include "nsStringGlue.h" michael@0: michael@0: #ifdef XP_WIN michael@0: // we want a wmain entry point michael@0: #include "nsWindowsWMain.cpp" michael@0: #define snprintf _snprintf michael@0: #define strcasecmp _stricmp michael@0: #endif michael@0: michael@0: #ifdef MOZ_WIDGET_GONK michael@0: #include "GonkDisplay.h" michael@0: #endif michael@0: michael@0: #include "BinaryPath.h" michael@0: michael@0: #include "nsXPCOMPrivate.h" // for MAXPATHLEN and XPCOM_DLL michael@0: michael@0: #ifdef MOZ_WIDGET_GONK michael@0: # include michael@0: #endif michael@0: michael@0: #include "mozilla/Telemetry.h" michael@0: #include "mozilla/WindowsDllBlocklist.h" michael@0: michael@0: static void Output(const char *fmt, ... ) michael@0: { michael@0: va_list ap; michael@0: va_start(ap, fmt); michael@0: michael@0: #if defined(XP_WIN) && !MOZ_WINCONSOLE michael@0: char16_t msg[2048]; michael@0: _vsnwprintf(msg, sizeof(msg)/sizeof(msg[0]), NS_ConvertUTF8toUTF16(fmt).get(), ap); michael@0: MessageBoxW(nullptr, msg, L"XULRunner", MB_OK | MB_ICONERROR); michael@0: #else michael@0: vfprintf(stderr, fmt, ap); michael@0: #endif michael@0: michael@0: va_end(ap); michael@0: } michael@0: michael@0: /** michael@0: * Return true if |arg| matches the given argument name. michael@0: */ michael@0: static bool IsArg(const char* arg, const char* s) michael@0: { michael@0: if (*arg == '-') michael@0: { michael@0: if (*++arg == '-') michael@0: ++arg; michael@0: return !strcasecmp(arg, s); michael@0: } michael@0: michael@0: #if defined(XP_WIN) michael@0: if (*arg == '/') michael@0: return !strcasecmp(++arg, s); michael@0: #endif michael@0: michael@0: return false; michael@0: } michael@0: michael@0: /** michael@0: * A helper class which calls NS_LogInit/NS_LogTerm in its scope. michael@0: */ michael@0: class ScopedLogging michael@0: { michael@0: public: michael@0: ScopedLogging() { NS_LogInit(); } michael@0: ~ScopedLogging() { NS_LogTerm(); } michael@0: }; michael@0: michael@0: XRE_GetFileFromPathType XRE_GetFileFromPath; michael@0: XRE_CreateAppDataType XRE_CreateAppData; michael@0: XRE_FreeAppDataType XRE_FreeAppData; michael@0: XRE_TelemetryAccumulateType XRE_TelemetryAccumulate; michael@0: XRE_mainType XRE_main; michael@0: michael@0: static const nsDynamicFunctionLoad kXULFuncs[] = { michael@0: { "XRE_GetFileFromPath", (NSFuncPtr*) &XRE_GetFileFromPath }, michael@0: { "XRE_CreateAppData", (NSFuncPtr*) &XRE_CreateAppData }, michael@0: { "XRE_FreeAppData", (NSFuncPtr*) &XRE_FreeAppData }, michael@0: { "XRE_TelemetryAccumulate", (NSFuncPtr*) &XRE_TelemetryAccumulate }, michael@0: { "XRE_main", (NSFuncPtr*) &XRE_main }, michael@0: { nullptr, nullptr } michael@0: }; michael@0: michael@0: static int do_main(int argc, char* argv[]) michael@0: { michael@0: nsCOMPtr appini; michael@0: nsresult rv; michael@0: michael@0: // Allow firefox.exe to launch XULRunner apps via -app michael@0: // Note that -app must be the *first* argument. michael@0: const char *appDataFile = getenv("XUL_APP_FILE"); michael@0: if (appDataFile && *appDataFile) { michael@0: rv = XRE_GetFileFromPath(appDataFile, getter_AddRefs(appini)); michael@0: if (NS_FAILED(rv)) { michael@0: Output("Invalid path found: '%s'", appDataFile); michael@0: return 255; michael@0: } michael@0: } michael@0: else if (argc > 1 && IsArg(argv[1], "app")) { michael@0: if (argc == 2) { michael@0: Output("Incorrect number of arguments passed to -app"); michael@0: return 255; michael@0: } michael@0: michael@0: rv = XRE_GetFileFromPath(argv[2], getter_AddRefs(appini)); michael@0: if (NS_FAILED(rv)) { michael@0: Output("application.ini path not recognized: '%s'", argv[2]); michael@0: return 255; michael@0: } michael@0: michael@0: char appEnv[MAXPATHLEN]; michael@0: snprintf(appEnv, MAXPATHLEN, "XUL_APP_FILE=%s", argv[2]); michael@0: if (putenv(appEnv)) { michael@0: Output("Couldn't set %s.\n", appEnv); michael@0: return 255; michael@0: } michael@0: argv[2] = argv[0]; michael@0: argv += 2; michael@0: argc -= 2; michael@0: } michael@0: michael@0: #ifdef MOZ_WIDGET_GONK michael@0: /* Called to start the boot animation */ michael@0: (void) mozilla::GetGonkDisplay(); michael@0: #endif michael@0: michael@0: if (appini) { michael@0: nsXREAppData *appData; michael@0: rv = XRE_CreateAppData(appini, &appData); michael@0: if (NS_FAILED(rv)) { michael@0: Output("Couldn't read application.ini"); michael@0: return 255; michael@0: } michael@0: int result = XRE_main(argc, argv, appData, 0); michael@0: XRE_FreeAppData(appData); michael@0: return result; michael@0: } michael@0: michael@0: return XRE_main(argc, argv, &sAppData, 0); michael@0: } michael@0: michael@0: int main(int argc, char* argv[]) michael@0: { michael@0: char exePath[MAXPATHLEN]; michael@0: michael@0: #ifdef MOZ_WIDGET_GONK michael@0: // This creates a ThreadPool for binder ipc. A ThreadPool is necessary to michael@0: // receive binder calls, though not necessary to send binder calls. michael@0: // ProcessState::Self() also needs to be called once on the main thread to michael@0: // register the main thread with the binder driver. michael@0: android::ProcessState::self()->startThreadPool(); michael@0: #endif michael@0: michael@0: nsresult rv = mozilla::BinaryPath::Get(argv[0], exePath); michael@0: if (NS_FAILED(rv)) { michael@0: Output("Couldn't calculate the application directory.\n"); michael@0: return 255; michael@0: } michael@0: michael@0: char *lastSlash = strrchr(exePath, XPCOM_FILE_PATH_SEPARATOR[0]); michael@0: if (!lastSlash || ((lastSlash - exePath) + sizeof(XPCOM_DLL) + 1 > MAXPATHLEN)) michael@0: return 255; michael@0: michael@0: strcpy(++lastSlash, XPCOM_DLL); michael@0: michael@0: #if defined(XP_UNIX) michael@0: // If the b2g app is launched from adb shell, then the shell will wind michael@0: // up being the process group controller. This means that we can't send michael@0: // signals to the process group (useful for profiling). michael@0: // We ignore the return value since setsid() fails if we're already the michael@0: // process group controller (the normal situation). michael@0: (void)setsid(); michael@0: #endif michael@0: michael@0: int gotCounters; michael@0: #if defined(XP_UNIX) michael@0: struct rusage initialRUsage; michael@0: gotCounters = !getrusage(RUSAGE_SELF, &initialRUsage); michael@0: #elif defined(XP_WIN) michael@0: IO_COUNTERS ioCounters; michael@0: gotCounters = GetProcessIoCounters(GetCurrentProcess(), &ioCounters); michael@0: #endif michael@0: michael@0: #ifdef HAS_DLL_BLOCKLIST michael@0: DllBlocklist_Initialize(); michael@0: #endif michael@0: michael@0: // We do this because of data in bug 771745 michael@0: XPCOMGlueEnablePreload(); michael@0: michael@0: rv = XPCOMGlueStartup(exePath); michael@0: if (NS_FAILED(rv)) { michael@0: Output("Couldn't load XPCOM.\n"); michael@0: return 255; michael@0: } michael@0: // Reset exePath so that it is the directory name and not the xpcom dll name michael@0: *lastSlash = 0; michael@0: michael@0: rv = XPCOMGlueLoadXULFunctions(kXULFuncs); michael@0: if (NS_FAILED(rv)) { michael@0: Output("Couldn't load XRE functions.\n"); michael@0: return 255; michael@0: } michael@0: michael@0: if (gotCounters) { michael@0: #if defined(XP_WIN) michael@0: XRE_TelemetryAccumulate(mozilla::Telemetry::EARLY_GLUESTARTUP_READ_OPS, michael@0: int(ioCounters.ReadOperationCount)); michael@0: XRE_TelemetryAccumulate(mozilla::Telemetry::EARLY_GLUESTARTUP_READ_TRANSFER, michael@0: int(ioCounters.ReadTransferCount / 1024)); michael@0: IO_COUNTERS newIoCounters; michael@0: if (GetProcessIoCounters(GetCurrentProcess(), &newIoCounters)) { michael@0: XRE_TelemetryAccumulate(mozilla::Telemetry::GLUESTARTUP_READ_OPS, michael@0: int(newIoCounters.ReadOperationCount - ioCounters.ReadOperationCount)); michael@0: XRE_TelemetryAccumulate(mozilla::Telemetry::GLUESTARTUP_READ_TRANSFER, michael@0: int((newIoCounters.ReadTransferCount - ioCounters.ReadTransferCount) / 1024)); michael@0: } michael@0: #elif defined(XP_UNIX) michael@0: XRE_TelemetryAccumulate(mozilla::Telemetry::EARLY_GLUESTARTUP_HARD_FAULTS, michael@0: int(initialRUsage.ru_majflt)); michael@0: struct rusage newRUsage; michael@0: if (!getrusage(RUSAGE_SELF, &newRUsage)) { michael@0: XRE_TelemetryAccumulate(mozilla::Telemetry::GLUESTARTUP_HARD_FAULTS, michael@0: int(newRUsage.ru_majflt - initialRUsage.ru_majflt)); michael@0: } michael@0: #endif michael@0: } michael@0: michael@0: int result; michael@0: { michael@0: ScopedLogging log; michael@0: result = do_main(argc, argv); michael@0: } michael@0: michael@0: return result; michael@0: }