Wed, 31 Dec 2014 06:55:50 +0100
Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2
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 "application.ini.h" |
michael@0 | 8 | #include "nsXPCOMGlue.h" |
michael@0 | 9 | #if defined(XP_WIN) |
michael@0 | 10 | #include <windows.h> |
michael@0 | 11 | #include <stdlib.h> |
michael@0 | 12 | #elif defined(XP_UNIX) |
michael@0 | 13 | #include <sys/time.h> |
michael@0 | 14 | #include <sys/resource.h> |
michael@0 | 15 | #include <unistd.h> |
michael@0 | 16 | #endif |
michael@0 | 17 | |
michael@0 | 18 | #include <stdio.h> |
michael@0 | 19 | #include <stdarg.h> |
michael@0 | 20 | |
michael@0 | 21 | #include "nsCOMPtr.h" |
michael@0 | 22 | #include "nsIFile.h" |
michael@0 | 23 | #include "nsStringGlue.h" |
michael@0 | 24 | |
michael@0 | 25 | #ifdef XP_WIN |
michael@0 | 26 | // we want a wmain entry point |
michael@0 | 27 | #include "nsWindowsWMain.cpp" |
michael@0 | 28 | #define snprintf _snprintf |
michael@0 | 29 | #define strcasecmp _stricmp |
michael@0 | 30 | #endif |
michael@0 | 31 | |
michael@0 | 32 | #ifdef MOZ_WIDGET_GONK |
michael@0 | 33 | #include "GonkDisplay.h" |
michael@0 | 34 | #endif |
michael@0 | 35 | |
michael@0 | 36 | #include "BinaryPath.h" |
michael@0 | 37 | |
michael@0 | 38 | #include "nsXPCOMPrivate.h" // for MAXPATHLEN and XPCOM_DLL |
michael@0 | 39 | |
michael@0 | 40 | #ifdef MOZ_WIDGET_GONK |
michael@0 | 41 | # include <binder/ProcessState.h> |
michael@0 | 42 | #endif |
michael@0 | 43 | |
michael@0 | 44 | #include "mozilla/Telemetry.h" |
michael@0 | 45 | #include "mozilla/WindowsDllBlocklist.h" |
michael@0 | 46 | |
michael@0 | 47 | static void Output(const char *fmt, ... ) |
michael@0 | 48 | { |
michael@0 | 49 | va_list ap; |
michael@0 | 50 | va_start(ap, fmt); |
michael@0 | 51 | |
michael@0 | 52 | #if defined(XP_WIN) && !MOZ_WINCONSOLE |
michael@0 | 53 | char16_t msg[2048]; |
michael@0 | 54 | _vsnwprintf(msg, sizeof(msg)/sizeof(msg[0]), NS_ConvertUTF8toUTF16(fmt).get(), ap); |
michael@0 | 55 | MessageBoxW(nullptr, msg, L"XULRunner", MB_OK | MB_ICONERROR); |
michael@0 | 56 | #else |
michael@0 | 57 | vfprintf(stderr, fmt, ap); |
michael@0 | 58 | #endif |
michael@0 | 59 | |
michael@0 | 60 | va_end(ap); |
michael@0 | 61 | } |
michael@0 | 62 | |
michael@0 | 63 | /** |
michael@0 | 64 | * Return true if |arg| matches the given argument name. |
michael@0 | 65 | */ |
michael@0 | 66 | static bool IsArg(const char* arg, const char* s) |
michael@0 | 67 | { |
michael@0 | 68 | if (*arg == '-') |
michael@0 | 69 | { |
michael@0 | 70 | if (*++arg == '-') |
michael@0 | 71 | ++arg; |
michael@0 | 72 | return !strcasecmp(arg, s); |
michael@0 | 73 | } |
michael@0 | 74 | |
michael@0 | 75 | #if defined(XP_WIN) |
michael@0 | 76 | if (*arg == '/') |
michael@0 | 77 | return !strcasecmp(++arg, s); |
michael@0 | 78 | #endif |
michael@0 | 79 | |
michael@0 | 80 | return false; |
michael@0 | 81 | } |
michael@0 | 82 | |
michael@0 | 83 | /** |
michael@0 | 84 | * A helper class which calls NS_LogInit/NS_LogTerm in its scope. |
michael@0 | 85 | */ |
michael@0 | 86 | class ScopedLogging |
michael@0 | 87 | { |
michael@0 | 88 | public: |
michael@0 | 89 | ScopedLogging() { NS_LogInit(); } |
michael@0 | 90 | ~ScopedLogging() { NS_LogTerm(); } |
michael@0 | 91 | }; |
michael@0 | 92 | |
michael@0 | 93 | XRE_GetFileFromPathType XRE_GetFileFromPath; |
michael@0 | 94 | XRE_CreateAppDataType XRE_CreateAppData; |
michael@0 | 95 | XRE_FreeAppDataType XRE_FreeAppData; |
michael@0 | 96 | XRE_TelemetryAccumulateType XRE_TelemetryAccumulate; |
michael@0 | 97 | XRE_mainType XRE_main; |
michael@0 | 98 | |
michael@0 | 99 | static const nsDynamicFunctionLoad kXULFuncs[] = { |
michael@0 | 100 | { "XRE_GetFileFromPath", (NSFuncPtr*) &XRE_GetFileFromPath }, |
michael@0 | 101 | { "XRE_CreateAppData", (NSFuncPtr*) &XRE_CreateAppData }, |
michael@0 | 102 | { "XRE_FreeAppData", (NSFuncPtr*) &XRE_FreeAppData }, |
michael@0 | 103 | { "XRE_TelemetryAccumulate", (NSFuncPtr*) &XRE_TelemetryAccumulate }, |
michael@0 | 104 | { "XRE_main", (NSFuncPtr*) &XRE_main }, |
michael@0 | 105 | { nullptr, nullptr } |
michael@0 | 106 | }; |
michael@0 | 107 | |
michael@0 | 108 | static int do_main(int argc, char* argv[]) |
michael@0 | 109 | { |
michael@0 | 110 | nsCOMPtr<nsIFile> appini; |
michael@0 | 111 | nsresult rv; |
michael@0 | 112 | |
michael@0 | 113 | // Allow firefox.exe to launch XULRunner apps via -app <application.ini> |
michael@0 | 114 | // Note that -app must be the *first* argument. |
michael@0 | 115 | const char *appDataFile = getenv("XUL_APP_FILE"); |
michael@0 | 116 | if (appDataFile && *appDataFile) { |
michael@0 | 117 | rv = XRE_GetFileFromPath(appDataFile, getter_AddRefs(appini)); |
michael@0 | 118 | if (NS_FAILED(rv)) { |
michael@0 | 119 | Output("Invalid path found: '%s'", appDataFile); |
michael@0 | 120 | return 255; |
michael@0 | 121 | } |
michael@0 | 122 | } |
michael@0 | 123 | else if (argc > 1 && IsArg(argv[1], "app")) { |
michael@0 | 124 | if (argc == 2) { |
michael@0 | 125 | Output("Incorrect number of arguments passed to -app"); |
michael@0 | 126 | return 255; |
michael@0 | 127 | } |
michael@0 | 128 | |
michael@0 | 129 | rv = XRE_GetFileFromPath(argv[2], getter_AddRefs(appini)); |
michael@0 | 130 | if (NS_FAILED(rv)) { |
michael@0 | 131 | Output("application.ini path not recognized: '%s'", argv[2]); |
michael@0 | 132 | return 255; |
michael@0 | 133 | } |
michael@0 | 134 | |
michael@0 | 135 | char appEnv[MAXPATHLEN]; |
michael@0 | 136 | snprintf(appEnv, MAXPATHLEN, "XUL_APP_FILE=%s", argv[2]); |
michael@0 | 137 | if (putenv(appEnv)) { |
michael@0 | 138 | Output("Couldn't set %s.\n", appEnv); |
michael@0 | 139 | return 255; |
michael@0 | 140 | } |
michael@0 | 141 | argv[2] = argv[0]; |
michael@0 | 142 | argv += 2; |
michael@0 | 143 | argc -= 2; |
michael@0 | 144 | } |
michael@0 | 145 | |
michael@0 | 146 | #ifdef MOZ_WIDGET_GONK |
michael@0 | 147 | /* Called to start the boot animation */ |
michael@0 | 148 | (void) mozilla::GetGonkDisplay(); |
michael@0 | 149 | #endif |
michael@0 | 150 | |
michael@0 | 151 | if (appini) { |
michael@0 | 152 | nsXREAppData *appData; |
michael@0 | 153 | rv = XRE_CreateAppData(appini, &appData); |
michael@0 | 154 | if (NS_FAILED(rv)) { |
michael@0 | 155 | Output("Couldn't read application.ini"); |
michael@0 | 156 | return 255; |
michael@0 | 157 | } |
michael@0 | 158 | int result = XRE_main(argc, argv, appData, 0); |
michael@0 | 159 | XRE_FreeAppData(appData); |
michael@0 | 160 | return result; |
michael@0 | 161 | } |
michael@0 | 162 | |
michael@0 | 163 | return XRE_main(argc, argv, &sAppData, 0); |
michael@0 | 164 | } |
michael@0 | 165 | |
michael@0 | 166 | int main(int argc, char* argv[]) |
michael@0 | 167 | { |
michael@0 | 168 | char exePath[MAXPATHLEN]; |
michael@0 | 169 | |
michael@0 | 170 | #ifdef MOZ_WIDGET_GONK |
michael@0 | 171 | // This creates a ThreadPool for binder ipc. A ThreadPool is necessary to |
michael@0 | 172 | // receive binder calls, though not necessary to send binder calls. |
michael@0 | 173 | // ProcessState::Self() also needs to be called once on the main thread to |
michael@0 | 174 | // register the main thread with the binder driver. |
michael@0 | 175 | android::ProcessState::self()->startThreadPool(); |
michael@0 | 176 | #endif |
michael@0 | 177 | |
michael@0 | 178 | nsresult rv = mozilla::BinaryPath::Get(argv[0], exePath); |
michael@0 | 179 | if (NS_FAILED(rv)) { |
michael@0 | 180 | Output("Couldn't calculate the application directory.\n"); |
michael@0 | 181 | return 255; |
michael@0 | 182 | } |
michael@0 | 183 | |
michael@0 | 184 | char *lastSlash = strrchr(exePath, XPCOM_FILE_PATH_SEPARATOR[0]); |
michael@0 | 185 | if (!lastSlash || ((lastSlash - exePath) + sizeof(XPCOM_DLL) + 1 > MAXPATHLEN)) |
michael@0 | 186 | return 255; |
michael@0 | 187 | |
michael@0 | 188 | strcpy(++lastSlash, XPCOM_DLL); |
michael@0 | 189 | |
michael@0 | 190 | #if defined(XP_UNIX) |
michael@0 | 191 | // If the b2g app is launched from adb shell, then the shell will wind |
michael@0 | 192 | // up being the process group controller. This means that we can't send |
michael@0 | 193 | // signals to the process group (useful for profiling). |
michael@0 | 194 | // We ignore the return value since setsid() fails if we're already the |
michael@0 | 195 | // process group controller (the normal situation). |
michael@0 | 196 | (void)setsid(); |
michael@0 | 197 | #endif |
michael@0 | 198 | |
michael@0 | 199 | int gotCounters; |
michael@0 | 200 | #if defined(XP_UNIX) |
michael@0 | 201 | struct rusage initialRUsage; |
michael@0 | 202 | gotCounters = !getrusage(RUSAGE_SELF, &initialRUsage); |
michael@0 | 203 | #elif defined(XP_WIN) |
michael@0 | 204 | IO_COUNTERS ioCounters; |
michael@0 | 205 | gotCounters = GetProcessIoCounters(GetCurrentProcess(), &ioCounters); |
michael@0 | 206 | #endif |
michael@0 | 207 | |
michael@0 | 208 | #ifdef HAS_DLL_BLOCKLIST |
michael@0 | 209 | DllBlocklist_Initialize(); |
michael@0 | 210 | #endif |
michael@0 | 211 | |
michael@0 | 212 | // We do this because of data in bug 771745 |
michael@0 | 213 | XPCOMGlueEnablePreload(); |
michael@0 | 214 | |
michael@0 | 215 | rv = XPCOMGlueStartup(exePath); |
michael@0 | 216 | if (NS_FAILED(rv)) { |
michael@0 | 217 | Output("Couldn't load XPCOM.\n"); |
michael@0 | 218 | return 255; |
michael@0 | 219 | } |
michael@0 | 220 | // Reset exePath so that it is the directory name and not the xpcom dll name |
michael@0 | 221 | *lastSlash = 0; |
michael@0 | 222 | |
michael@0 | 223 | rv = XPCOMGlueLoadXULFunctions(kXULFuncs); |
michael@0 | 224 | if (NS_FAILED(rv)) { |
michael@0 | 225 | Output("Couldn't load XRE functions.\n"); |
michael@0 | 226 | return 255; |
michael@0 | 227 | } |
michael@0 | 228 | |
michael@0 | 229 | if (gotCounters) { |
michael@0 | 230 | #if defined(XP_WIN) |
michael@0 | 231 | XRE_TelemetryAccumulate(mozilla::Telemetry::EARLY_GLUESTARTUP_READ_OPS, |
michael@0 | 232 | int(ioCounters.ReadOperationCount)); |
michael@0 | 233 | XRE_TelemetryAccumulate(mozilla::Telemetry::EARLY_GLUESTARTUP_READ_TRANSFER, |
michael@0 | 234 | int(ioCounters.ReadTransferCount / 1024)); |
michael@0 | 235 | IO_COUNTERS newIoCounters; |
michael@0 | 236 | if (GetProcessIoCounters(GetCurrentProcess(), &newIoCounters)) { |
michael@0 | 237 | XRE_TelemetryAccumulate(mozilla::Telemetry::GLUESTARTUP_READ_OPS, |
michael@0 | 238 | int(newIoCounters.ReadOperationCount - ioCounters.ReadOperationCount)); |
michael@0 | 239 | XRE_TelemetryAccumulate(mozilla::Telemetry::GLUESTARTUP_READ_TRANSFER, |
michael@0 | 240 | int((newIoCounters.ReadTransferCount - ioCounters.ReadTransferCount) / 1024)); |
michael@0 | 241 | } |
michael@0 | 242 | #elif defined(XP_UNIX) |
michael@0 | 243 | XRE_TelemetryAccumulate(mozilla::Telemetry::EARLY_GLUESTARTUP_HARD_FAULTS, |
michael@0 | 244 | int(initialRUsage.ru_majflt)); |
michael@0 | 245 | struct rusage newRUsage; |
michael@0 | 246 | if (!getrusage(RUSAGE_SELF, &newRUsage)) { |
michael@0 | 247 | XRE_TelemetryAccumulate(mozilla::Telemetry::GLUESTARTUP_HARD_FAULTS, |
michael@0 | 248 | int(newRUsage.ru_majflt - initialRUsage.ru_majflt)); |
michael@0 | 249 | } |
michael@0 | 250 | #endif |
michael@0 | 251 | } |
michael@0 | 252 | |
michael@0 | 253 | int result; |
michael@0 | 254 | { |
michael@0 | 255 | ScopedLogging log; |
michael@0 | 256 | result = do_main(argc, argv); |
michael@0 | 257 | } |
michael@0 | 258 | |
michael@0 | 259 | return result; |
michael@0 | 260 | } |