|
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/. */ |
|
5 |
|
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 |
|
20 |
|
21 #ifdef XP_MACOSX |
|
22 #include <mach/mach_time.h> |
|
23 #include "MacQuirks.h" |
|
24 #endif |
|
25 |
|
26 #include <stdio.h> |
|
27 #include <stdarg.h> |
|
28 #include <time.h> |
|
29 |
|
30 #include "nsCOMPtr.h" |
|
31 #include "nsIFile.h" |
|
32 #include "nsStringGlue.h" |
|
33 |
|
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 |
|
37 |
|
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" |
|
45 |
|
46 #include "nsXPCOMPrivate.h" // for MAXPATHLEN and XPCOM_DLL |
|
47 |
|
48 #include "mozilla/Telemetry.h" |
|
49 #include "mozilla/WindowsDllBlocklist.h" |
|
50 |
|
51 using namespace mozilla; |
|
52 |
|
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 |
|
60 |
|
61 static void Output(const char *fmt, ... ) |
|
62 { |
|
63 va_list ap; |
|
64 va_start(ap, fmt); |
|
65 |
|
66 #ifndef XP_WIN |
|
67 vfprintf(stderr, fmt, ap); |
|
68 #else |
|
69 char msg[2048]; |
|
70 vsnprintf_s(msg, _countof(msg), _TRUNCATE, fmt, ap); |
|
71 |
|
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 |
|
97 |
|
98 va_end(ap); |
|
99 } |
|
100 |
|
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 } |
|
112 |
|
113 #if defined(XP_WIN) |
|
114 if (*arg == '/') |
|
115 return !strcasecmp(++arg, s); |
|
116 #endif |
|
117 |
|
118 return false; |
|
119 } |
|
120 |
|
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); |
|
138 |
|
139 if (winOut == INVALID_HANDLE_VALUE) { |
|
140 OutputDebugStringW(L"Could not create named logging pipe.\n"); |
|
141 return; |
|
142 } |
|
143 |
|
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 |
|
154 |
|
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; |
|
162 |
|
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 }; |
|
173 |
|
174 static int do_main(int argc, char* argv[], nsIFile *xreDirectory) |
|
175 { |
|
176 nsCOMPtr<nsIFile> appini; |
|
177 nsresult rv; |
|
178 uint32_t mainFlags = 0; |
|
179 |
|
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 } |
|
195 |
|
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 } |
|
201 |
|
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 } |
|
212 |
|
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 } |
|
226 |
|
227 bool metroOnDesktop = false; |
|
228 |
|
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 |
|
260 |
|
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 } |
|
270 |
|
271 nsCOMPtr<nsIFile> greDir; |
|
272 exeFile->GetParent(getter_AddRefs(greDir)); |
|
273 |
|
274 nsCOMPtr<nsIFile> appSubdir; |
|
275 greDir->Clone(getter_AddRefs(appSubdir)); |
|
276 appSubdir->Append(NS_LITERAL_STRING(kDesktopFolder)); |
|
277 |
|
278 SetStrongPtr(appData.directory, static_cast<nsIFile*>(appSubdir.get())); |
|
279 // xreDirectory already has a refcount from NS_NewLocalFile |
|
280 appData.xreDirectory = xreDirectory; |
|
281 |
|
282 return XRE_main(argc, argv, &appData, mainFlags); |
|
283 } |
|
284 |
|
285 // Metro browser launch |
|
286 #ifdef MOZ_METRO |
|
287 nsCOMPtr<nsIFile> iniFile, appSubdir; |
|
288 |
|
289 xreDirectory->Clone(getter_AddRefs(iniFile)); |
|
290 xreDirectory->Clone(getter_AddRefs(appSubdir)); |
|
291 |
|
292 iniFile->Append(NS_LITERAL_STRING(kMetroFolder)); |
|
293 iniFile->Append(NS_LITERAL_STRING(kMetroAppIniFilename)); |
|
294 |
|
295 appSubdir->Append(NS_LITERAL_STRING(kMetroFolder)); |
|
296 |
|
297 nsAutoCString path; |
|
298 if (NS_FAILED(iniFile->GetNativePath(path))) { |
|
299 Output("Couldn't get ini file path.\n"); |
|
300 return 255; |
|
301 } |
|
302 |
|
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 } |
|
309 |
|
310 SetStrongPtr(appData->directory, static_cast<nsIFile*>(appSubdir.get())); |
|
311 // xreDirectory already has a refcount from NS_NewLocalFile |
|
312 appData->xreDirectory = xreDirectory; |
|
313 |
|
314 #ifdef XP_WIN |
|
315 if (!metroOnDesktop) { |
|
316 nsCOMPtr<nsIFile> testFile; |
|
317 |
|
318 xreDirectory->Clone(getter_AddRefs(testFile)); |
|
319 testFile->Append(NS_LITERAL_STRING(kMetroTestFile)); |
|
320 |
|
321 nsAutoCString path; |
|
322 if (NS_FAILED(testFile->GetNativePath(path))) { |
|
323 Output("Couldn't get test file path.\n"); |
|
324 return 255; |
|
325 } |
|
326 |
|
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); |
|
345 |
|
346 // Build new args array |
|
347 char* newArgv[20]; |
|
348 int newArgc = 1; |
|
349 |
|
350 memset(newArgv, 0, sizeof(newArgv)); |
|
351 |
|
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--; |
|
368 |
|
369 // attach browser stdout to metrotestharness stdout |
|
370 AttachToTestHarness(); |
|
371 |
|
372 int result = XRE_main(newArgc, newArgv, appData, mainFlags); |
|
373 XRE_FreeAppData(appData); |
|
374 return result; |
|
375 } |
|
376 } |
|
377 #endif |
|
378 |
|
379 int result = XRE_main(argc, argv, appData, mainFlags); |
|
380 XRE_FreeAppData(appData); |
|
381 return result; |
|
382 #endif |
|
383 |
|
384 NS_NOTREACHED("browser do_main failed to pickup proper initialization"); |
|
385 return 255; |
|
386 } |
|
387 |
|
388 #ifdef XP_WIN |
|
389 |
|
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; |
|
395 |
|
396 /** |
|
397 * Higher part of the 64-bit value of MozGetTickCount64, |
|
398 * incremented atomically. |
|
399 */ |
|
400 static DWORD sLastGTCRollover = 0; |
|
401 |
|
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(); |
|
413 |
|
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; |
|
418 |
|
419 sLastGTCResult = GTC; |
|
420 return (ULONGLONG)sLastGTCRollover << 32 | sLastGTCResult; |
|
421 } |
|
422 |
|
423 typedef ULONGLONG (WINAPI* GetTickCount64_t)(); |
|
424 static GetTickCount64_t sGetTickCount64 = nullptr; |
|
425 |
|
426 #endif |
|
427 |
|
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); |
|
438 |
|
439 HMODULE kernelDLL = GetModuleHandleW(L"kernel32.dll"); |
|
440 sGetTickCount64 = reinterpret_cast<GetTickCount64_t> |
|
441 (GetProcAddress(kernelDLL, "GetTickCount64")); |
|
442 |
|
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 } |
|
448 |
|
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); |
|
455 |
|
456 if (rv != 0) { |
|
457 return 0; |
|
458 } |
|
459 |
|
460 uint64_t baseNs = (uint64_t)ts.tv_sec * 1000000000; |
|
461 return baseNs + (uint64_t)ts.tv_nsec; |
|
462 #endif |
|
463 } |
|
464 |
|
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 } |
|
477 |
|
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]; |
|
487 |
|
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 } |
|
493 |
|
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; |
|
497 |
|
498 strcpy(lastSlash + 1, XPCOM_PATH); |
|
499 lastSlash += sizeof(XPCOM_PATH) - sizeof(XPCOM_DLL); |
|
500 |
|
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); |
|
519 |
|
520 if (xulurl) { |
|
521 CFURLRef xpcomurl = |
|
522 CFURLCreateCopyAppendingPathComponent(nullptr, xulurl, |
|
523 CFSTR("libxpcom.dylib"), |
|
524 false); |
|
525 |
|
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 } |
|
547 |
|
548 // We do this because of data in bug 771745 |
|
549 XPCOMGlueEnablePreload(); |
|
550 |
|
551 rv = XPCOMGlueStartup(exePath); |
|
552 if (NS_FAILED(rv)) { |
|
553 Output("Couldn't load XPCOM.\n"); |
|
554 return rv; |
|
555 } |
|
556 |
|
557 rv = XPCOMGlueLoadXULFunctions(kXULFuncs); |
|
558 if (NS_FAILED(rv)) { |
|
559 Output("Couldn't load XRE functions.\n"); |
|
560 return rv; |
|
561 } |
|
562 |
|
563 NS_LogInit(); |
|
564 |
|
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 |
|
574 |
|
575 return rv; |
|
576 } |
|
577 |
|
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(); |
|
584 |
|
585 #ifdef XP_MACOSX |
|
586 TriggerQuirks(); |
|
587 #endif |
|
588 |
|
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 |
|
597 |
|
598 nsIFile *xreDirectory; |
|
599 |
|
600 #ifdef HAS_DLL_BLOCKLIST |
|
601 DllBlocklist_Initialize(); |
|
602 |
|
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 |
|
611 |
|
612 nsresult rv = InitXPCOMGlue(argv[0], &xreDirectory); |
|
613 if (NS_FAILED(rv)) { |
|
614 return 255; |
|
615 } |
|
616 |
|
617 XRE_StartupTimelineRecord(mozilla::StartupTimeline::START, start); |
|
618 |
|
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 } |
|
642 |
|
643 int result = do_main(argc, argv, xreDirectory); |
|
644 |
|
645 NS_LogTerm(); |
|
646 |
|
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 |
|
655 |
|
656 return result; |
|
657 } |