|
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 #if defined(MOZ_WIDGET_QT) |
|
7 #include <QGuiApplication> |
|
8 #include <QStringList> |
|
9 #include "nsQAppInstance.h" |
|
10 #endif // MOZ_WIDGET_QT |
|
11 |
|
12 #include "mozilla/dom/ContentParent.h" |
|
13 #include "mozilla/dom/ContentChild.h" |
|
14 |
|
15 #include "mozilla/ArrayUtils.h" |
|
16 #include "mozilla/Attributes.h" |
|
17 #include "mozilla/IOInterposer.h" |
|
18 #include "mozilla/Likely.h" |
|
19 #include "mozilla/Poison.h" |
|
20 #include "mozilla/Preferences.h" |
|
21 #include "mozilla/Telemetry.h" |
|
22 |
|
23 #include "nsAppRunner.h" |
|
24 #include "mozilla/AppData.h" |
|
25 #include "nsUpdateDriver.h" |
|
26 #include "ProfileReset.h" |
|
27 |
|
28 #ifdef MOZ_INSTRUMENT_EVENT_LOOP |
|
29 #include "EventTracer.h" |
|
30 #endif |
|
31 |
|
32 #ifdef XP_MACOSX |
|
33 #include "nsVersionComparator.h" |
|
34 #include "MacLaunchHelper.h" |
|
35 #include "MacApplicationDelegate.h" |
|
36 #include "MacAutoreleasePool.h" |
|
37 // these are needed for sysctl |
|
38 #include <sys/types.h> |
|
39 #include <sys/sysctl.h> |
|
40 #endif |
|
41 |
|
42 #include "prmem.h" |
|
43 #include "prnetdb.h" |
|
44 #include "prprf.h" |
|
45 #include "prproces.h" |
|
46 #include "prenv.h" |
|
47 |
|
48 #include "nsIAppShellService.h" |
|
49 #include "nsIAppStartup.h" |
|
50 #include "nsIAppStartupNotifier.h" |
|
51 #include "nsIMutableArray.h" |
|
52 #include "nsICategoryManager.h" |
|
53 #include "nsIChromeRegistry.h" |
|
54 #include "nsICommandLineRunner.h" |
|
55 #include "nsIComponentManager.h" |
|
56 #include "nsIComponentRegistrar.h" |
|
57 #include "nsIContentHandler.h" |
|
58 #include "nsIDialogParamBlock.h" |
|
59 #include "nsIDOMWindow.h" |
|
60 #include "mozilla/ModuleUtils.h" |
|
61 #include "nsIIOService2.h" |
|
62 #include "nsIObserverService.h" |
|
63 #include "nsINativeAppSupport.h" |
|
64 #include "nsIProcess.h" |
|
65 #include "nsIProfileUnlocker.h" |
|
66 #include "nsIPromptService.h" |
|
67 #include "nsIServiceManager.h" |
|
68 #include "nsIStringBundle.h" |
|
69 #include "nsISupportsPrimitives.h" |
|
70 #include "nsIToolkitChromeRegistry.h" |
|
71 #include "nsIToolkitProfile.h" |
|
72 #include "nsIToolkitProfileService.h" |
|
73 #include "nsIURI.h" |
|
74 #include "nsIWindowCreator.h" |
|
75 #include "nsIWindowMediator.h" |
|
76 #include "nsIWindowWatcher.h" |
|
77 #include "nsIXULAppInfo.h" |
|
78 #include "nsIXULRuntime.h" |
|
79 #include "nsPIDOMWindow.h" |
|
80 #include "nsIBaseWindow.h" |
|
81 #include "nsIWidget.h" |
|
82 #include "nsIDocShell.h" |
|
83 #include "nsAppShellCID.h" |
|
84 #include "mozilla/scache/StartupCache.h" |
|
85 |
|
86 #include "mozilla/unused.h" |
|
87 |
|
88 #ifdef XP_WIN |
|
89 #include "nsIWinAppHelper.h" |
|
90 #include <windows.h> |
|
91 #include "cairo/cairo-features.h" |
|
92 #include "mozilla/WindowsVersion.h" |
|
93 #ifdef MOZ_METRO |
|
94 #include <roapi.h> |
|
95 #endif |
|
96 |
|
97 #ifndef PROCESS_DEP_ENABLE |
|
98 #define PROCESS_DEP_ENABLE 0x1 |
|
99 #endif |
|
100 #endif |
|
101 |
|
102 #include "nsCRT.h" |
|
103 #include "nsCOMPtr.h" |
|
104 #include "nsDirectoryServiceDefs.h" |
|
105 #include "nsDirectoryServiceUtils.h" |
|
106 #include "nsEmbedCID.h" |
|
107 #include "nsNetUtil.h" |
|
108 #include "nsReadableUtils.h" |
|
109 #include "nsXPCOM.h" |
|
110 #include "nsXPCOMCIDInternal.h" |
|
111 #include "nsXPIDLString.h" |
|
112 #include "nsPrintfCString.h" |
|
113 #include "nsVersionComparator.h" |
|
114 |
|
115 #include "nsAppDirectoryServiceDefs.h" |
|
116 #include "nsXULAppAPI.h" |
|
117 #include "nsXREDirProvider.h" |
|
118 #include "nsToolkitCompsCID.h" |
|
119 |
|
120 #if defined(XP_WIN) && defined(MOZ_METRO) |
|
121 #include "updatehelper.h" |
|
122 #endif |
|
123 |
|
124 #include "nsINIParser.h" |
|
125 #include "mozilla/Omnijar.h" |
|
126 #include "mozilla/StartupTimeline.h" |
|
127 #include "mozilla/LateWriteChecks.h" |
|
128 |
|
129 #include <stdlib.h> |
|
130 |
|
131 #ifdef XP_UNIX |
|
132 #include <sys/stat.h> |
|
133 #include <unistd.h> |
|
134 #include <pwd.h> |
|
135 #endif |
|
136 |
|
137 #ifdef XP_WIN |
|
138 #include <process.h> |
|
139 #include <shlobj.h> |
|
140 #include "nsThreadUtils.h" |
|
141 #include <comdef.h> |
|
142 #include <wbemidl.h> |
|
143 #endif |
|
144 |
|
145 #ifdef XP_MACOSX |
|
146 #include "nsILocalFileMac.h" |
|
147 #include "nsCommandLineServiceMac.h" |
|
148 #endif |
|
149 |
|
150 // for X remote support |
|
151 #ifdef MOZ_ENABLE_XREMOTE |
|
152 #include "XRemoteClient.h" |
|
153 #include "nsIRemoteService.h" |
|
154 #endif |
|
155 |
|
156 #ifdef NS_TRACE_MALLOC |
|
157 #include "nsTraceMalloc.h" |
|
158 #endif |
|
159 |
|
160 #if defined(DEBUG) && defined(XP_WIN32) |
|
161 #include <malloc.h> |
|
162 #endif |
|
163 |
|
164 #if defined (XP_MACOSX) |
|
165 #include <Carbon/Carbon.h> |
|
166 #endif |
|
167 |
|
168 #ifdef DEBUG |
|
169 #include "prlog.h" |
|
170 #endif |
|
171 |
|
172 #ifdef MOZ_JPROF |
|
173 #include "jprof.h" |
|
174 #endif |
|
175 |
|
176 #ifdef MOZ_CRASHREPORTER |
|
177 #include "nsExceptionHandler.h" |
|
178 #include "nsICrashReporter.h" |
|
179 #define NS_CRASHREPORTER_CONTRACTID "@mozilla.org/toolkit/crash-reporter;1" |
|
180 #include "nsIPrefService.h" |
|
181 #endif |
|
182 |
|
183 #include "base/command_line.h" |
|
184 #ifdef MOZ_ENABLE_TESTS |
|
185 #include "GTestRunner.h" |
|
186 #endif |
|
187 |
|
188 #ifdef MOZ_WIDGET_ANDROID |
|
189 #include "AndroidBridge.h" |
|
190 #endif |
|
191 |
|
192 extern uint32_t gRestartMode; |
|
193 extern void InstallSignalHandlers(const char *ProgramName); |
|
194 #include "nsX11ErrorHandler.h" |
|
195 |
|
196 #define FILE_COMPATIBILITY_INFO NS_LITERAL_CSTRING("compatibility.ini") |
|
197 #define FILE_INVALIDATE_CACHES NS_LITERAL_CSTRING(".purgecaches") |
|
198 |
|
199 int gArgc; |
|
200 char **gArgv; |
|
201 |
|
202 static const char gToolkitVersion[] = NS_STRINGIFY(GRE_MILESTONE); |
|
203 static const char gToolkitBuildID[] = NS_STRINGIFY(GRE_BUILDID); |
|
204 |
|
205 static nsIProfileLock* gProfileLock; |
|
206 |
|
207 int gRestartArgc; |
|
208 char **gRestartArgv; |
|
209 |
|
210 #ifdef MOZ_WIDGET_QT |
|
211 static int gQtOnlyArgc; |
|
212 static char **gQtOnlyArgv; |
|
213 #endif |
|
214 |
|
215 #if defined(MOZ_WIDGET_GTK) |
|
216 #if defined(DEBUG) || defined(NS_BUILD_REFCNT_LOGGING) \ |
|
217 || defined(NS_TRACE_MALLOC) |
|
218 #define CLEANUP_MEMORY 1 |
|
219 #define PANGO_ENABLE_BACKEND |
|
220 #include <pango/pangofc-fontmap.h> |
|
221 #endif |
|
222 #include <gtk/gtk.h> |
|
223 #ifdef MOZ_X11 |
|
224 #include <gdk/gdkx.h> |
|
225 #endif /* MOZ_X11 */ |
|
226 #include "nsGTKToolkit.h" |
|
227 #include <fontconfig/fontconfig.h> |
|
228 #endif |
|
229 #include "BinaryPath.h" |
|
230 |
|
231 #ifdef MOZ_LINKER |
|
232 extern "C" MFBT_API bool IsSignalHandlingBroken(); |
|
233 #endif |
|
234 |
|
235 namespace mozilla { |
|
236 int (*RunGTest)() = 0; |
|
237 } |
|
238 |
|
239 using namespace mozilla; |
|
240 using mozilla::unused; |
|
241 using mozilla::scache::StartupCache; |
|
242 using mozilla::dom::ContentParent; |
|
243 using mozilla::dom::ContentChild; |
|
244 |
|
245 // Save literal putenv string to environment variable. |
|
246 static void |
|
247 SaveToEnv(const char *putenv) |
|
248 { |
|
249 char *expr = strdup(putenv); |
|
250 if (expr) |
|
251 PR_SetEnv(expr); |
|
252 // We intentionally leak |expr| here since it is required by PR_SetEnv. |
|
253 } |
|
254 |
|
255 // Tests that an environment variable exists and has a value |
|
256 static bool |
|
257 EnvHasValue(const char *name) |
|
258 { |
|
259 const char *val = PR_GetEnv(name); |
|
260 return (val && *val); |
|
261 } |
|
262 |
|
263 // Save the given word to the specified environment variable. |
|
264 static void |
|
265 SaveWordToEnv(const char *name, const nsACString & word) |
|
266 { |
|
267 char *expr = PR_smprintf("%s=%s", name, PromiseFlatCString(word).get()); |
|
268 if (expr) |
|
269 PR_SetEnv(expr); |
|
270 // We intentionally leak |expr| here since it is required by PR_SetEnv. |
|
271 } |
|
272 |
|
273 // Save the path of the given file to the specified environment variable. |
|
274 static void |
|
275 SaveFileToEnv(const char *name, nsIFile *file) |
|
276 { |
|
277 #ifdef XP_WIN |
|
278 nsAutoString path; |
|
279 file->GetPath(path); |
|
280 SetEnvironmentVariableW(NS_ConvertASCIItoUTF16(name).get(), path.get()); |
|
281 #else |
|
282 nsAutoCString path; |
|
283 file->GetNativePath(path); |
|
284 SaveWordToEnv(name, path); |
|
285 #endif |
|
286 } |
|
287 |
|
288 // Load the path of a file saved with SaveFileToEnv |
|
289 static already_AddRefed<nsIFile> |
|
290 GetFileFromEnv(const char *name) |
|
291 { |
|
292 nsresult rv; |
|
293 nsCOMPtr<nsIFile> file; |
|
294 |
|
295 #ifdef XP_WIN |
|
296 WCHAR path[_MAX_PATH]; |
|
297 if (!GetEnvironmentVariableW(NS_ConvertASCIItoUTF16(name).get(), |
|
298 path, _MAX_PATH)) |
|
299 return nullptr; |
|
300 |
|
301 rv = NS_NewLocalFile(nsDependentString(path), true, getter_AddRefs(file)); |
|
302 if (NS_FAILED(rv)) |
|
303 return nullptr; |
|
304 |
|
305 return file.forget(); |
|
306 #else |
|
307 const char *arg = PR_GetEnv(name); |
|
308 if (!arg || !*arg) |
|
309 return nullptr; |
|
310 |
|
311 rv = NS_NewNativeLocalFile(nsDependentCString(arg), true, |
|
312 getter_AddRefs(file)); |
|
313 if (NS_FAILED(rv)) |
|
314 return nullptr; |
|
315 |
|
316 return file.forget(); |
|
317 #endif |
|
318 } |
|
319 |
|
320 // Save the path of the given word to the specified environment variable |
|
321 // provided the environment variable does not have a value. |
|
322 static void |
|
323 SaveWordToEnvIfUnset(const char *name, const nsACString & word) |
|
324 { |
|
325 if (!EnvHasValue(name)) |
|
326 SaveWordToEnv(name, word); |
|
327 } |
|
328 |
|
329 // Save the path of the given file to the specified environment variable |
|
330 // provided the environment variable does not have a value. |
|
331 static void |
|
332 SaveFileToEnvIfUnset(const char *name, nsIFile *file) |
|
333 { |
|
334 if (!EnvHasValue(name)) |
|
335 SaveFileToEnv(name, file); |
|
336 } |
|
337 |
|
338 static bool |
|
339 strimatch(const char* lowerstr, const char* mixedstr) |
|
340 { |
|
341 while(*lowerstr) { |
|
342 if (!*mixedstr) return false; // mixedstr is shorter |
|
343 if (tolower(*mixedstr) != *lowerstr) return false; // no match |
|
344 |
|
345 ++lowerstr; |
|
346 ++mixedstr; |
|
347 } |
|
348 |
|
349 if (*mixedstr) return false; // lowerstr is shorter |
|
350 |
|
351 return true; |
|
352 } |
|
353 |
|
354 /** |
|
355 * Output a string to the user. This method is really only meant to be used to |
|
356 * output last-ditch error messages designed for developers NOT END USERS. |
|
357 * |
|
358 * @param isError |
|
359 * Pass true to indicate severe errors. |
|
360 * @param fmt |
|
361 * printf-style format string followed by arguments. |
|
362 */ |
|
363 static void Output(bool isError, const char *fmt, ... ) |
|
364 { |
|
365 va_list ap; |
|
366 va_start(ap, fmt); |
|
367 |
|
368 #if defined(XP_WIN) && !MOZ_WINCONSOLE |
|
369 char *msg = PR_vsmprintf(fmt, ap); |
|
370 if (msg) |
|
371 { |
|
372 UINT flags = MB_OK; |
|
373 if (isError) |
|
374 flags |= MB_ICONERROR; |
|
375 else |
|
376 flags |= MB_ICONINFORMATION; |
|
377 |
|
378 wchar_t wide_msg[1024]; |
|
379 MultiByteToWideChar(CP_ACP, |
|
380 0, |
|
381 msg, |
|
382 -1, |
|
383 wide_msg, |
|
384 sizeof(wide_msg) / sizeof(wchar_t)); |
|
385 |
|
386 MessageBoxW(nullptr, wide_msg, L"XULRunner", flags); |
|
387 PR_smprintf_free(msg); |
|
388 } |
|
389 #else |
|
390 vfprintf(stderr, fmt, ap); |
|
391 #endif |
|
392 |
|
393 va_end(ap); |
|
394 } |
|
395 |
|
396 enum RemoteResult { |
|
397 REMOTE_NOT_FOUND = 0, |
|
398 REMOTE_FOUND = 1, |
|
399 REMOTE_ARG_BAD = 2 |
|
400 }; |
|
401 |
|
402 enum ArgResult { |
|
403 ARG_NONE = 0, |
|
404 ARG_FOUND = 1, |
|
405 ARG_BAD = 2 // you wanted a param, but there isn't one |
|
406 }; |
|
407 |
|
408 static void RemoveArg(char **argv) |
|
409 { |
|
410 do { |
|
411 *argv = *(argv + 1); |
|
412 ++argv; |
|
413 } while (*argv); |
|
414 |
|
415 --gArgc; |
|
416 } |
|
417 |
|
418 /** |
|
419 * Check for a commandline flag. If the flag takes a parameter, the |
|
420 * parameter is returned in aParam. Flags may be in the form -arg or |
|
421 * --arg (or /arg on win32). |
|
422 * |
|
423 * @param aArg the parameter to check. Must be lowercase. |
|
424 * @param aCheckOSInt if true returns ARG_BAD if the osint argument is present |
|
425 * when aArg is also present. |
|
426 * @param aParam if non-null, the -arg <data> will be stored in this pointer. |
|
427 * This is *not* allocated, but rather a pointer to the argv data. |
|
428 * @param aRemArg if true, the argument is removed from the gArgv array. |
|
429 */ |
|
430 static ArgResult |
|
431 CheckArg(const char* aArg, bool aCheckOSInt = false, const char **aParam = nullptr, bool aRemArg = true) |
|
432 { |
|
433 NS_ABORT_IF_FALSE(gArgv, "gArgv must be initialized before CheckArg()"); |
|
434 |
|
435 char **curarg = gArgv + 1; // skip argv[0] |
|
436 ArgResult ar = ARG_NONE; |
|
437 |
|
438 while (*curarg) { |
|
439 char *arg = curarg[0]; |
|
440 |
|
441 if (arg[0] == '-' |
|
442 #if defined(XP_WIN) |
|
443 || *arg == '/' |
|
444 #endif |
|
445 ) { |
|
446 ++arg; |
|
447 if (*arg == '-') |
|
448 ++arg; |
|
449 |
|
450 if (strimatch(aArg, arg)) { |
|
451 if (aRemArg) |
|
452 RemoveArg(curarg); |
|
453 if (!aParam) { |
|
454 ar = ARG_FOUND; |
|
455 break; |
|
456 } |
|
457 |
|
458 if (*curarg) { |
|
459 if (**curarg == '-' |
|
460 #if defined(XP_WIN) |
|
461 || **curarg == '/' |
|
462 #endif |
|
463 ) |
|
464 return ARG_BAD; |
|
465 |
|
466 *aParam = *curarg; |
|
467 if (aRemArg) |
|
468 RemoveArg(curarg); |
|
469 ar = ARG_FOUND; |
|
470 break; |
|
471 } |
|
472 return ARG_BAD; |
|
473 } |
|
474 } |
|
475 |
|
476 ++curarg; |
|
477 } |
|
478 |
|
479 if (aCheckOSInt && ar == ARG_FOUND) { |
|
480 ArgResult arOSInt = CheckArg("osint"); |
|
481 if (arOSInt == ARG_FOUND) { |
|
482 ar = ARG_BAD; |
|
483 PR_fprintf(PR_STDERR, "Error: argument -osint is invalid\n"); |
|
484 } |
|
485 } |
|
486 |
|
487 return ar; |
|
488 } |
|
489 |
|
490 #if defined(XP_WIN) |
|
491 /** |
|
492 * Check for a commandline flag from the windows shell and remove it from the |
|
493 * argv used when restarting. Flags MUST be in the form -arg. |
|
494 * |
|
495 * @param aArg the parameter to check. Must be lowercase. |
|
496 */ |
|
497 static ArgResult |
|
498 CheckArgShell(const char* aArg) |
|
499 { |
|
500 char **curarg = gRestartArgv + 1; // skip argv[0] |
|
501 |
|
502 while (*curarg) { |
|
503 char *arg = curarg[0]; |
|
504 |
|
505 if (arg[0] == '-') { |
|
506 ++arg; |
|
507 |
|
508 if (strimatch(aArg, arg)) { |
|
509 do { |
|
510 *curarg = *(curarg + 1); |
|
511 ++curarg; |
|
512 } while (*curarg); |
|
513 |
|
514 --gRestartArgc; |
|
515 |
|
516 return ARG_FOUND; |
|
517 } |
|
518 } |
|
519 |
|
520 ++curarg; |
|
521 } |
|
522 |
|
523 return ARG_NONE; |
|
524 } |
|
525 |
|
526 /** |
|
527 * Enabled Native App Support to process DDE messages when the app needs to |
|
528 * restart and the app has been launched by the Windows shell to open an url. |
|
529 * When aWait is false this will process the DDE events manually. This prevents |
|
530 * Windows from displaying an error message due to the DDE message not being |
|
531 * acknowledged. |
|
532 */ |
|
533 static void |
|
534 ProcessDDE(nsINativeAppSupport* aNative, bool aWait) |
|
535 { |
|
536 // When the app is launched by the windows shell the windows shell |
|
537 // expects the app to be available for DDE messages and if it isn't |
|
538 // windows displays an error dialog. To prevent the error the DDE server |
|
539 // is enabled and pending events are processed when the app needs to |
|
540 // restart after it was launched by the shell with the requestpending |
|
541 // argument. The requestpending pending argument is removed to |
|
542 // differentiate it from being launched when an app restart is not |
|
543 // required. |
|
544 ArgResult ar; |
|
545 ar = CheckArgShell("requestpending"); |
|
546 if (ar == ARG_FOUND) { |
|
547 aNative->Enable(); // enable win32 DDE responses |
|
548 if (aWait) { |
|
549 nsIThread *thread = NS_GetCurrentThread(); |
|
550 // This is just a guesstimate based on testing different values. |
|
551 // If count is 8 or less windows will display an error dialog. |
|
552 int32_t count = 20; |
|
553 while(--count >= 0) { |
|
554 NS_ProcessNextEvent(thread); |
|
555 PR_Sleep(PR_MillisecondsToInterval(1)); |
|
556 } |
|
557 } |
|
558 } |
|
559 } |
|
560 #endif |
|
561 |
|
562 /** |
|
563 * Determines if there is support for showing the profile manager |
|
564 * |
|
565 * @return true in all environments except for Windows Metro |
|
566 */ |
|
567 static bool |
|
568 CanShowProfileManager() |
|
569 { |
|
570 #if defined(XP_WIN) |
|
571 return XRE_GetWindowsEnvironment() == WindowsEnvironmentType_Desktop; |
|
572 #else |
|
573 return true; |
|
574 #endif |
|
575 } |
|
576 |
|
577 |
|
578 bool gSafeMode = false; |
|
579 |
|
580 /** |
|
581 * The nsXULAppInfo object implements nsIFactory so that it can be its own |
|
582 * singleton. |
|
583 */ |
|
584 class nsXULAppInfo : public nsIXULAppInfo, |
|
585 #ifdef XP_WIN |
|
586 public nsIWinAppHelper, |
|
587 #endif |
|
588 #ifdef MOZ_CRASHREPORTER |
|
589 public nsICrashReporter, |
|
590 #endif |
|
591 public nsIXULRuntime |
|
592 |
|
593 { |
|
594 public: |
|
595 MOZ_CONSTEXPR nsXULAppInfo() {} |
|
596 NS_DECL_ISUPPORTS_INHERITED |
|
597 NS_DECL_NSIXULAPPINFO |
|
598 NS_DECL_NSIXULRUNTIME |
|
599 #ifdef MOZ_CRASHREPORTER |
|
600 NS_DECL_NSICRASHREPORTER |
|
601 #endif |
|
602 #ifdef XP_WIN |
|
603 NS_DECL_NSIWINAPPHELPER |
|
604 #endif |
|
605 }; |
|
606 |
|
607 NS_INTERFACE_MAP_BEGIN(nsXULAppInfo) |
|
608 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXULRuntime) |
|
609 NS_INTERFACE_MAP_ENTRY(nsIXULRuntime) |
|
610 #ifdef XP_WIN |
|
611 NS_INTERFACE_MAP_ENTRY(nsIWinAppHelper) |
|
612 #endif |
|
613 #ifdef MOZ_CRASHREPORTER |
|
614 NS_INTERFACE_MAP_ENTRY(nsICrashReporter) |
|
615 #endif |
|
616 NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIXULAppInfo, gAppData || |
|
617 XRE_GetProcessType() == GeckoProcessType_Content) |
|
618 NS_INTERFACE_MAP_END |
|
619 |
|
620 NS_IMETHODIMP_(MozExternalRefCountType) |
|
621 nsXULAppInfo::AddRef() |
|
622 { |
|
623 return 1; |
|
624 } |
|
625 |
|
626 NS_IMETHODIMP_(MozExternalRefCountType) |
|
627 nsXULAppInfo::Release() |
|
628 { |
|
629 return 1; |
|
630 } |
|
631 |
|
632 NS_IMETHODIMP |
|
633 nsXULAppInfo::GetVendor(nsACString& aResult) |
|
634 { |
|
635 if (XRE_GetProcessType() == GeckoProcessType_Content) { |
|
636 return NS_ERROR_NOT_AVAILABLE; |
|
637 } |
|
638 aResult.Assign(gAppData->vendor); |
|
639 |
|
640 return NS_OK; |
|
641 } |
|
642 |
|
643 NS_IMETHODIMP |
|
644 nsXULAppInfo::GetName(nsACString& aResult) |
|
645 { |
|
646 if (XRE_GetProcessType() == GeckoProcessType_Content) { |
|
647 ContentChild* cc = ContentChild::GetSingleton(); |
|
648 aResult = cc->GetAppInfo().name; |
|
649 return NS_OK; |
|
650 } |
|
651 aResult.Assign(gAppData->name); |
|
652 |
|
653 return NS_OK; |
|
654 } |
|
655 |
|
656 NS_IMETHODIMP |
|
657 nsXULAppInfo::GetID(nsACString& aResult) |
|
658 { |
|
659 if (XRE_GetProcessType() == GeckoProcessType_Content) { |
|
660 return NS_ERROR_NOT_AVAILABLE; |
|
661 } |
|
662 aResult.Assign(gAppData->ID); |
|
663 |
|
664 return NS_OK; |
|
665 } |
|
666 |
|
667 NS_IMETHODIMP |
|
668 nsXULAppInfo::GetVersion(nsACString& aResult) |
|
669 { |
|
670 if (XRE_GetProcessType() == GeckoProcessType_Content) { |
|
671 ContentChild* cc = ContentChild::GetSingleton(); |
|
672 aResult = cc->GetAppInfo().version; |
|
673 return NS_OK; |
|
674 } |
|
675 aResult.Assign(gAppData->version); |
|
676 |
|
677 return NS_OK; |
|
678 } |
|
679 |
|
680 NS_IMETHODIMP |
|
681 nsXULAppInfo::GetPlatformVersion(nsACString& aResult) |
|
682 { |
|
683 aResult.Assign(gToolkitVersion); |
|
684 |
|
685 return NS_OK; |
|
686 } |
|
687 |
|
688 NS_IMETHODIMP |
|
689 nsXULAppInfo::GetAppBuildID(nsACString& aResult) |
|
690 { |
|
691 if (XRE_GetProcessType() == GeckoProcessType_Content) { |
|
692 ContentChild* cc = ContentChild::GetSingleton(); |
|
693 aResult = cc->GetAppInfo().buildID; |
|
694 return NS_OK; |
|
695 } |
|
696 aResult.Assign(gAppData->buildID); |
|
697 |
|
698 return NS_OK; |
|
699 } |
|
700 |
|
701 NS_IMETHODIMP |
|
702 nsXULAppInfo::GetPlatformBuildID(nsACString& aResult) |
|
703 { |
|
704 aResult.Assign(gToolkitBuildID); |
|
705 |
|
706 return NS_OK; |
|
707 } |
|
708 |
|
709 NS_IMETHODIMP |
|
710 nsXULAppInfo::GetUAName(nsACString& aResult) |
|
711 { |
|
712 if (XRE_GetProcessType() == GeckoProcessType_Content) { |
|
713 ContentChild* cc = ContentChild::GetSingleton(); |
|
714 aResult = cc->GetAppInfo().UAName; |
|
715 return NS_OK; |
|
716 } |
|
717 aResult.Assign(gAppData->UAName); |
|
718 |
|
719 return NS_OK; |
|
720 } |
|
721 |
|
722 NS_IMETHODIMP |
|
723 nsXULAppInfo::GetLogConsoleErrors(bool *aResult) |
|
724 { |
|
725 *aResult = gLogConsoleErrors; |
|
726 return NS_OK; |
|
727 } |
|
728 |
|
729 NS_IMETHODIMP |
|
730 nsXULAppInfo::SetLogConsoleErrors(bool aValue) |
|
731 { |
|
732 gLogConsoleErrors = aValue; |
|
733 return NS_OK; |
|
734 } |
|
735 |
|
736 NS_IMETHODIMP |
|
737 nsXULAppInfo::GetInSafeMode(bool *aResult) |
|
738 { |
|
739 *aResult = gSafeMode; |
|
740 return NS_OK; |
|
741 } |
|
742 |
|
743 NS_IMETHODIMP |
|
744 nsXULAppInfo::GetOS(nsACString& aResult) |
|
745 { |
|
746 aResult.AssignLiteral(OS_TARGET); |
|
747 return NS_OK; |
|
748 } |
|
749 |
|
750 NS_IMETHODIMP |
|
751 nsXULAppInfo::GetXPCOMABI(nsACString& aResult) |
|
752 { |
|
753 #ifdef TARGET_XPCOM_ABI |
|
754 aResult.AssignLiteral(TARGET_XPCOM_ABI); |
|
755 return NS_OK; |
|
756 #else |
|
757 return NS_ERROR_NOT_AVAILABLE; |
|
758 #endif |
|
759 } |
|
760 |
|
761 NS_IMETHODIMP |
|
762 nsXULAppInfo::GetWidgetToolkit(nsACString& aResult) |
|
763 { |
|
764 aResult.AssignLiteral(MOZ_WIDGET_TOOLKIT); |
|
765 return NS_OK; |
|
766 } |
|
767 |
|
768 // Ensure that the GeckoProcessType enum, defined in xpcom/build/nsXULAppAPI.h, |
|
769 // is synchronized with the const unsigned longs defined in |
|
770 // xpcom/system/nsIXULRuntime.idl. |
|
771 #define SYNC_ENUMS(a,b) \ |
|
772 static_assert(nsIXULRuntime::PROCESS_TYPE_ ## a == \ |
|
773 static_cast<int>(GeckoProcessType_ ## b), \ |
|
774 "GeckoProcessType in nsXULAppAPI.h not synchronized with nsIXULRuntime.idl"); |
|
775 |
|
776 SYNC_ENUMS(DEFAULT, Default) |
|
777 SYNC_ENUMS(PLUGIN, Plugin) |
|
778 SYNC_ENUMS(CONTENT, Content) |
|
779 SYNC_ENUMS(IPDLUNITTEST, IPDLUnitTest) |
|
780 |
|
781 // .. and ensure that that is all of them: |
|
782 static_assert(GeckoProcessType_IPDLUnitTest + 1 == GeckoProcessType_End, |
|
783 "Did not find the final GeckoProcessType"); |
|
784 |
|
785 NS_IMETHODIMP |
|
786 nsXULAppInfo::GetProcessType(uint32_t* aResult) |
|
787 { |
|
788 NS_ENSURE_ARG_POINTER(aResult); |
|
789 *aResult = XRE_GetProcessType(); |
|
790 return NS_OK; |
|
791 } |
|
792 |
|
793 NS_IMETHODIMP |
|
794 nsXULAppInfo::GetProcessID(uint32_t* aResult) |
|
795 { |
|
796 #ifdef XP_WIN |
|
797 *aResult = GetCurrentProcessId(); |
|
798 #else |
|
799 *aResult = getpid(); |
|
800 #endif |
|
801 return NS_OK; |
|
802 } |
|
803 |
|
804 static bool gBrowserTabsRemote = false; |
|
805 static bool gBrowserTabsRemoteInitialized = false; |
|
806 |
|
807 NS_IMETHODIMP |
|
808 nsXULAppInfo::GetBrowserTabsRemote(bool* aResult) |
|
809 { |
|
810 *aResult = BrowserTabsRemote(); |
|
811 return NS_OK; |
|
812 } |
|
813 |
|
814 NS_IMETHODIMP |
|
815 nsXULAppInfo::EnsureContentProcess() |
|
816 { |
|
817 if (XRE_GetProcessType() != GeckoProcessType_Default) |
|
818 return NS_ERROR_NOT_AVAILABLE; |
|
819 |
|
820 nsRefPtr<ContentParent> unused = ContentParent::GetNewOrUsed(); |
|
821 return NS_OK; |
|
822 } |
|
823 |
|
824 NS_IMETHODIMP |
|
825 nsXULAppInfo::InvalidateCachesOnRestart() |
|
826 { |
|
827 nsCOMPtr<nsIFile> file; |
|
828 nsresult rv = NS_GetSpecialDirectory(NS_APP_PROFILE_DIR_STARTUP, |
|
829 getter_AddRefs(file)); |
|
830 if (NS_FAILED(rv)) |
|
831 return rv; |
|
832 if (!file) |
|
833 return NS_ERROR_NOT_AVAILABLE; |
|
834 |
|
835 file->AppendNative(FILE_COMPATIBILITY_INFO); |
|
836 |
|
837 nsINIParser parser; |
|
838 rv = parser.Init(file); |
|
839 if (NS_FAILED(rv)) { |
|
840 // This fails if compatibility.ini is not there, so we'll |
|
841 // flush the caches on the next restart anyways. |
|
842 return NS_OK; |
|
843 } |
|
844 |
|
845 nsAutoCString buf; |
|
846 rv = parser.GetString("Compatibility", "InvalidateCaches", buf); |
|
847 |
|
848 if (NS_FAILED(rv)) { |
|
849 PRFileDesc *fd = nullptr; |
|
850 file->OpenNSPRFileDesc(PR_RDWR | PR_APPEND, 0600, &fd); |
|
851 if (!fd) { |
|
852 NS_ERROR("could not create output stream"); |
|
853 return NS_ERROR_NOT_AVAILABLE; |
|
854 } |
|
855 static const char kInvalidationHeader[] = NS_LINEBREAK "InvalidateCaches=1" NS_LINEBREAK; |
|
856 PR_Write(fd, kInvalidationHeader, sizeof(kInvalidationHeader) - 1); |
|
857 PR_Close(fd); |
|
858 } |
|
859 return NS_OK; |
|
860 } |
|
861 |
|
862 NS_IMETHODIMP |
|
863 nsXULAppInfo::GetReplacedLockTime(PRTime *aReplacedLockTime) |
|
864 { |
|
865 if (!gProfileLock) |
|
866 return NS_ERROR_NOT_AVAILABLE; |
|
867 gProfileLock->GetReplacedLockTime(aReplacedLockTime); |
|
868 return NS_OK; |
|
869 } |
|
870 |
|
871 NS_IMETHODIMP |
|
872 nsXULAppInfo::GetLastRunCrashID(nsAString &aLastRunCrashID) |
|
873 { |
|
874 #ifdef MOZ_CRASHREPORTER |
|
875 CrashReporter::GetLastRunCrashID(aLastRunCrashID); |
|
876 return NS_OK; |
|
877 #else |
|
878 return NS_ERROR_NOT_IMPLEMENTED; |
|
879 #endif |
|
880 } |
|
881 |
|
882 NS_IMETHODIMP |
|
883 nsXULAppInfo::GetIsReleaseBuild(bool* aResult) |
|
884 { |
|
885 #ifdef RELEASE_BUILD |
|
886 *aResult = true; |
|
887 #else |
|
888 *aResult = false; |
|
889 #endif |
|
890 return NS_OK; |
|
891 } |
|
892 |
|
893 NS_IMETHODIMP |
|
894 nsXULAppInfo::GetIsOfficialBranding(bool* aResult) |
|
895 { |
|
896 #ifdef MOZ_OFFICIAL_BRANDING |
|
897 *aResult = true; |
|
898 #else |
|
899 *aResult = false; |
|
900 #endif |
|
901 return NS_OK; |
|
902 } |
|
903 |
|
904 NS_IMETHODIMP |
|
905 nsXULAppInfo::GetDefaultUpdateChannel(nsACString& aResult) |
|
906 { |
|
907 aResult.AssignLiteral(NS_STRINGIFY(MOZ_UPDATE_CHANNEL)); |
|
908 return NS_OK; |
|
909 } |
|
910 |
|
911 NS_IMETHODIMP |
|
912 nsXULAppInfo::GetDistributionID(nsACString& aResult) |
|
913 { |
|
914 aResult.AssignLiteral(MOZ_DISTRIBUTION_ID); |
|
915 return NS_OK; |
|
916 } |
|
917 |
|
918 #ifdef XP_WIN |
|
919 // Matches the enum in WinNT.h for the Vista SDK but renamed so that we can |
|
920 // safely build with the Vista SDK and without it. |
|
921 typedef enum |
|
922 { |
|
923 VistaTokenElevationTypeDefault = 1, |
|
924 VistaTokenElevationTypeFull, |
|
925 VistaTokenElevationTypeLimited |
|
926 } VISTA_TOKEN_ELEVATION_TYPE; |
|
927 |
|
928 // avoid collision with TokeElevationType enum in WinNT.h |
|
929 // of the Vista SDK |
|
930 #define VistaTokenElevationType static_cast< TOKEN_INFORMATION_CLASS >( 18 ) |
|
931 |
|
932 NS_IMETHODIMP |
|
933 nsXULAppInfo::GetUserCanElevate(bool *aUserCanElevate) |
|
934 { |
|
935 HANDLE hToken; |
|
936 |
|
937 VISTA_TOKEN_ELEVATION_TYPE elevationType; |
|
938 DWORD dwSize; |
|
939 |
|
940 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken) || |
|
941 !GetTokenInformation(hToken, VistaTokenElevationType, &elevationType, |
|
942 sizeof(elevationType), &dwSize)) { |
|
943 *aUserCanElevate = false; |
|
944 } |
|
945 else { |
|
946 // The possible values returned for elevationType and their meanings are: |
|
947 // TokenElevationTypeDefault: The token does not have a linked token |
|
948 // (e.g. UAC disabled or a standard user, so they can't be elevated) |
|
949 // TokenElevationTypeFull: The token is linked to an elevated token |
|
950 // (e.g. UAC is enabled and the user is already elevated so they can't |
|
951 // be elevated again) |
|
952 // TokenElevationTypeLimited: The token is linked to a limited token |
|
953 // (e.g. UAC is enabled and the user is not elevated, so they can be |
|
954 // elevated) |
|
955 *aUserCanElevate = (elevationType == VistaTokenElevationTypeLimited); |
|
956 } |
|
957 |
|
958 if (hToken) |
|
959 CloseHandle(hToken); |
|
960 |
|
961 return NS_OK; |
|
962 } |
|
963 #endif |
|
964 |
|
965 #ifdef MOZ_CRASHREPORTER |
|
966 NS_IMETHODIMP |
|
967 nsXULAppInfo::GetEnabled(bool *aEnabled) |
|
968 { |
|
969 *aEnabled = CrashReporter::GetEnabled(); |
|
970 return NS_OK; |
|
971 } |
|
972 |
|
973 NS_IMETHODIMP |
|
974 nsXULAppInfo::SetEnabled(bool aEnabled) |
|
975 { |
|
976 if (aEnabled) { |
|
977 if (CrashReporter::GetEnabled()) |
|
978 // no point in erroring for double-enabling |
|
979 return NS_OK; |
|
980 |
|
981 nsCOMPtr<nsIFile> xreDirectory; |
|
982 if (gAppData) { |
|
983 xreDirectory = gAppData->xreDirectory; |
|
984 } |
|
985 else { |
|
986 // We didn't get started through XRE_Main, probably |
|
987 nsCOMPtr<nsIFile> greDir; |
|
988 NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(greDir)); |
|
989 if (!greDir) |
|
990 return NS_ERROR_FAILURE; |
|
991 |
|
992 xreDirectory = do_QueryInterface(greDir); |
|
993 if (!xreDirectory) |
|
994 return NS_ERROR_FAILURE; |
|
995 } |
|
996 return CrashReporter::SetExceptionHandler(xreDirectory, true); |
|
997 } |
|
998 else { |
|
999 if (!CrashReporter::GetEnabled()) |
|
1000 // no point in erroring for double-disabling |
|
1001 return NS_OK; |
|
1002 |
|
1003 return CrashReporter::UnsetExceptionHandler(); |
|
1004 } |
|
1005 } |
|
1006 |
|
1007 NS_IMETHODIMP |
|
1008 nsXULAppInfo::GetServerURL(nsIURL** aServerURL) |
|
1009 { |
|
1010 if (!CrashReporter::GetEnabled()) |
|
1011 return NS_ERROR_NOT_INITIALIZED; |
|
1012 |
|
1013 nsAutoCString data; |
|
1014 if (!CrashReporter::GetServerURL(data)) { |
|
1015 return NS_ERROR_FAILURE; |
|
1016 } |
|
1017 nsCOMPtr<nsIURI> uri; |
|
1018 NS_NewURI(getter_AddRefs(uri), data); |
|
1019 if (!uri) |
|
1020 return NS_ERROR_FAILURE; |
|
1021 |
|
1022 nsCOMPtr<nsIURL> url; |
|
1023 url = do_QueryInterface(uri); |
|
1024 NS_ADDREF(*aServerURL = url); |
|
1025 |
|
1026 return NS_OK; |
|
1027 } |
|
1028 |
|
1029 NS_IMETHODIMP |
|
1030 nsXULAppInfo::SetServerURL(nsIURL* aServerURL) |
|
1031 { |
|
1032 bool schemeOk; |
|
1033 // only allow https or http URLs |
|
1034 nsresult rv = aServerURL->SchemeIs("https", &schemeOk); |
|
1035 NS_ENSURE_SUCCESS(rv, rv); |
|
1036 if (!schemeOk) { |
|
1037 rv = aServerURL->SchemeIs("http", &schemeOk); |
|
1038 NS_ENSURE_SUCCESS(rv, rv); |
|
1039 |
|
1040 if (!schemeOk) |
|
1041 return NS_ERROR_INVALID_ARG; |
|
1042 } |
|
1043 nsAutoCString spec; |
|
1044 rv = aServerURL->GetSpec(spec); |
|
1045 NS_ENSURE_SUCCESS(rv, rv); |
|
1046 |
|
1047 return CrashReporter::SetServerURL(spec); |
|
1048 } |
|
1049 |
|
1050 NS_IMETHODIMP |
|
1051 nsXULAppInfo::GetMinidumpPath(nsIFile** aMinidumpPath) |
|
1052 { |
|
1053 if (!CrashReporter::GetEnabled()) |
|
1054 return NS_ERROR_NOT_INITIALIZED; |
|
1055 |
|
1056 nsAutoString path; |
|
1057 if (!CrashReporter::GetMinidumpPath(path)) |
|
1058 return NS_ERROR_FAILURE; |
|
1059 |
|
1060 nsresult rv = NS_NewLocalFile(path, false, aMinidumpPath); |
|
1061 NS_ENSURE_SUCCESS(rv, rv); |
|
1062 return NS_OK; |
|
1063 } |
|
1064 |
|
1065 NS_IMETHODIMP |
|
1066 nsXULAppInfo::SetMinidumpPath(nsIFile* aMinidumpPath) |
|
1067 { |
|
1068 nsAutoString path; |
|
1069 nsresult rv = aMinidumpPath->GetPath(path); |
|
1070 NS_ENSURE_SUCCESS(rv, rv); |
|
1071 return CrashReporter::SetMinidumpPath(path); |
|
1072 } |
|
1073 |
|
1074 NS_IMETHODIMP |
|
1075 nsXULAppInfo::AnnotateCrashReport(const nsACString& key, |
|
1076 const nsACString& data) |
|
1077 { |
|
1078 return CrashReporter::AnnotateCrashReport(key, data); |
|
1079 } |
|
1080 |
|
1081 NS_IMETHODIMP |
|
1082 nsXULAppInfo::AppendAppNotesToCrashReport(const nsACString& data) |
|
1083 { |
|
1084 return CrashReporter::AppendAppNotesToCrashReport(data); |
|
1085 } |
|
1086 |
|
1087 NS_IMETHODIMP |
|
1088 nsXULAppInfo::RegisterAppMemory(uint64_t pointer, |
|
1089 uint64_t len) |
|
1090 { |
|
1091 return CrashReporter::RegisterAppMemory((void *)pointer, len); |
|
1092 } |
|
1093 |
|
1094 NS_IMETHODIMP |
|
1095 nsXULAppInfo::WriteMinidumpForException(void* aExceptionInfo) |
|
1096 { |
|
1097 #ifdef XP_WIN32 |
|
1098 return CrashReporter::WriteMinidumpForException(static_cast<EXCEPTION_POINTERS*>(aExceptionInfo)); |
|
1099 #else |
|
1100 return NS_ERROR_NOT_IMPLEMENTED; |
|
1101 #endif |
|
1102 } |
|
1103 |
|
1104 NS_IMETHODIMP |
|
1105 nsXULAppInfo::AppendObjCExceptionInfoToAppNotes(void* aException) |
|
1106 { |
|
1107 #ifdef XP_MACOSX |
|
1108 return CrashReporter::AppendObjCExceptionInfoToAppNotes(aException); |
|
1109 #else |
|
1110 return NS_ERROR_NOT_IMPLEMENTED; |
|
1111 #endif |
|
1112 } |
|
1113 |
|
1114 NS_IMETHODIMP |
|
1115 nsXULAppInfo::GetSubmitReports(bool* aEnabled) |
|
1116 { |
|
1117 return CrashReporter::GetSubmitReports(aEnabled); |
|
1118 } |
|
1119 |
|
1120 NS_IMETHODIMP |
|
1121 nsXULAppInfo::SetSubmitReports(bool aEnabled) |
|
1122 { |
|
1123 return CrashReporter::SetSubmitReports(aEnabled); |
|
1124 } |
|
1125 |
|
1126 NS_IMETHODIMP |
|
1127 nsXULAppInfo::UpdateCrashEventsDir() |
|
1128 { |
|
1129 CrashReporter::UpdateCrashEventsDir(); |
|
1130 return NS_OK; |
|
1131 } |
|
1132 |
|
1133 #endif |
|
1134 |
|
1135 static const nsXULAppInfo kAppInfo; |
|
1136 static nsresult AppInfoConstructor(nsISupports* aOuter, |
|
1137 REFNSIID aIID, void **aResult) |
|
1138 { |
|
1139 NS_ENSURE_NO_AGGREGATION(aOuter); |
|
1140 |
|
1141 return const_cast<nsXULAppInfo*>(&kAppInfo)-> |
|
1142 QueryInterface(aIID, aResult); |
|
1143 } |
|
1144 |
|
1145 bool gLogConsoleErrors = false; |
|
1146 |
|
1147 #define NS_ENSURE_TRUE_LOG(x, ret) \ |
|
1148 PR_BEGIN_MACRO \ |
|
1149 if (MOZ_UNLIKELY(!(x))) { \ |
|
1150 NS_WARNING("NS_ENSURE_TRUE(" #x ") failed"); \ |
|
1151 gLogConsoleErrors = true; \ |
|
1152 return ret; \ |
|
1153 } \ |
|
1154 PR_END_MACRO |
|
1155 |
|
1156 #define NS_ENSURE_SUCCESS_LOG(res, ret) \ |
|
1157 NS_ENSURE_TRUE_LOG(NS_SUCCEEDED(res), ret) |
|
1158 |
|
1159 /** |
|
1160 * Because we're starting/stopping XPCOM several times in different scenarios, |
|
1161 * this class is a stack-based critter that makes sure that XPCOM is shut down |
|
1162 * during early returns. |
|
1163 */ |
|
1164 |
|
1165 class ScopedXPCOMStartup |
|
1166 { |
|
1167 public: |
|
1168 ScopedXPCOMStartup() : |
|
1169 mServiceManager(nullptr) { } |
|
1170 ~ScopedXPCOMStartup(); |
|
1171 |
|
1172 nsresult Initialize(); |
|
1173 nsresult SetWindowCreator(nsINativeAppSupport* native); |
|
1174 |
|
1175 static nsresult CreateAppSupport(nsISupports* aOuter, REFNSIID aIID, void** aResult); |
|
1176 |
|
1177 private: |
|
1178 nsIServiceManager* mServiceManager; |
|
1179 static nsINativeAppSupport* gNativeAppSupport; |
|
1180 }; |
|
1181 |
|
1182 ScopedXPCOMStartup::~ScopedXPCOMStartup() |
|
1183 { |
|
1184 NS_IF_RELEASE(gNativeAppSupport); |
|
1185 |
|
1186 if (mServiceManager) { |
|
1187 #ifdef XP_MACOSX |
|
1188 // On OS X, we need a pool to catch cocoa objects that are autoreleased |
|
1189 // during teardown. |
|
1190 mozilla::MacAutoreleasePool pool; |
|
1191 #endif |
|
1192 |
|
1193 nsCOMPtr<nsIAppStartup> appStartup (do_GetService(NS_APPSTARTUP_CONTRACTID)); |
|
1194 if (appStartup) |
|
1195 appStartup->DestroyHiddenWindow(); |
|
1196 |
|
1197 gDirServiceProvider->DoShutdown(); |
|
1198 PROFILER_MARKER("Shutdown early"); |
|
1199 |
|
1200 WriteConsoleLog(); |
|
1201 |
|
1202 NS_ShutdownXPCOM(mServiceManager); |
|
1203 mServiceManager = nullptr; |
|
1204 } |
|
1205 } |
|
1206 |
|
1207 // {95d89e3e-a169-41a3-8e56-719978e15b12} |
|
1208 #define APPINFO_CID \ |
|
1209 { 0x95d89e3e, 0xa169, 0x41a3, { 0x8e, 0x56, 0x71, 0x99, 0x78, 0xe1, 0x5b, 0x12 } } |
|
1210 |
|
1211 // {0C4A446C-EE82-41f2-8D04-D366D2C7A7D4} |
|
1212 static const nsCID kNativeAppSupportCID = |
|
1213 { 0xc4a446c, 0xee82, 0x41f2, { 0x8d, 0x4, 0xd3, 0x66, 0xd2, 0xc7, 0xa7, 0xd4 } }; |
|
1214 |
|
1215 // {5F5E59CE-27BC-47eb-9D1F-B09CA9049836} |
|
1216 static const nsCID kProfileServiceCID = |
|
1217 { 0x5f5e59ce, 0x27bc, 0x47eb, { 0x9d, 0x1f, 0xb0, 0x9c, 0xa9, 0x4, 0x98, 0x36 } }; |
|
1218 |
|
1219 static already_AddRefed<nsIFactory> |
|
1220 ProfileServiceFactoryConstructor(const mozilla::Module& module, const mozilla::Module::CIDEntry& entry) |
|
1221 { |
|
1222 nsCOMPtr<nsIFactory> factory; |
|
1223 NS_NewToolkitProfileFactory(getter_AddRefs(factory)); |
|
1224 return factory.forget(); |
|
1225 } |
|
1226 |
|
1227 NS_DEFINE_NAMED_CID(APPINFO_CID); |
|
1228 |
|
1229 static const mozilla::Module::CIDEntry kXRECIDs[] = { |
|
1230 { &kAPPINFO_CID, false, nullptr, AppInfoConstructor }, |
|
1231 { &kProfileServiceCID, false, ProfileServiceFactoryConstructor, nullptr }, |
|
1232 { &kNativeAppSupportCID, false, nullptr, ScopedXPCOMStartup::CreateAppSupport }, |
|
1233 { nullptr } |
|
1234 }; |
|
1235 |
|
1236 static const mozilla::Module::ContractIDEntry kXREContracts[] = { |
|
1237 { XULAPPINFO_SERVICE_CONTRACTID, &kAPPINFO_CID }, |
|
1238 { XULRUNTIME_SERVICE_CONTRACTID, &kAPPINFO_CID }, |
|
1239 #ifdef MOZ_CRASHREPORTER |
|
1240 { NS_CRASHREPORTER_CONTRACTID, &kAPPINFO_CID }, |
|
1241 #endif |
|
1242 { NS_PROFILESERVICE_CONTRACTID, &kProfileServiceCID }, |
|
1243 { NS_NATIVEAPPSUPPORT_CONTRACTID, &kNativeAppSupportCID }, |
|
1244 { nullptr } |
|
1245 }; |
|
1246 |
|
1247 static const mozilla::Module kXREModule = { |
|
1248 mozilla::Module::kVersion, |
|
1249 kXRECIDs, |
|
1250 kXREContracts |
|
1251 }; |
|
1252 |
|
1253 NSMODULE_DEFN(Apprunner) = &kXREModule; |
|
1254 |
|
1255 nsresult |
|
1256 ScopedXPCOMStartup::Initialize() |
|
1257 { |
|
1258 NS_ASSERTION(gDirServiceProvider, "Should not get here!"); |
|
1259 |
|
1260 nsresult rv; |
|
1261 |
|
1262 rv = NS_InitXPCOM2(&mServiceManager, gDirServiceProvider->GetAppDir(), |
|
1263 gDirServiceProvider); |
|
1264 if (NS_FAILED(rv)) { |
|
1265 NS_ERROR("Couldn't start xpcom!"); |
|
1266 mServiceManager = nullptr; |
|
1267 } |
|
1268 else { |
|
1269 nsCOMPtr<nsIComponentRegistrar> reg = |
|
1270 do_QueryInterface(mServiceManager); |
|
1271 NS_ASSERTION(reg, "Service Manager doesn't QI to Registrar."); |
|
1272 } |
|
1273 |
|
1274 return rv; |
|
1275 } |
|
1276 |
|
1277 /** |
|
1278 * This is a little factory class that serves as a singleton-service-factory |
|
1279 * for the nativeappsupport object. |
|
1280 */ |
|
1281 class nsSingletonFactory MOZ_FINAL : public nsIFactory |
|
1282 { |
|
1283 public: |
|
1284 NS_DECL_ISUPPORTS |
|
1285 NS_DECL_NSIFACTORY |
|
1286 |
|
1287 nsSingletonFactory(nsISupports* aSingleton); |
|
1288 ~nsSingletonFactory() { } |
|
1289 |
|
1290 private: |
|
1291 nsCOMPtr<nsISupports> mSingleton; |
|
1292 }; |
|
1293 |
|
1294 nsSingletonFactory::nsSingletonFactory(nsISupports* aSingleton) |
|
1295 : mSingleton(aSingleton) |
|
1296 { |
|
1297 NS_ASSERTION(mSingleton, "Singleton was null!"); |
|
1298 } |
|
1299 |
|
1300 NS_IMPL_ISUPPORTS(nsSingletonFactory, nsIFactory) |
|
1301 |
|
1302 NS_IMETHODIMP |
|
1303 nsSingletonFactory::CreateInstance(nsISupports* aOuter, |
|
1304 const nsIID& aIID, |
|
1305 void* *aResult) |
|
1306 { |
|
1307 NS_ENSURE_NO_AGGREGATION(aOuter); |
|
1308 |
|
1309 return mSingleton->QueryInterface(aIID, aResult); |
|
1310 } |
|
1311 |
|
1312 NS_IMETHODIMP |
|
1313 nsSingletonFactory::LockFactory(bool) |
|
1314 { |
|
1315 return NS_OK; |
|
1316 } |
|
1317 |
|
1318 /** |
|
1319 * Set our windowcreator on the WindowWatcher service. |
|
1320 */ |
|
1321 nsresult |
|
1322 ScopedXPCOMStartup::SetWindowCreator(nsINativeAppSupport* native) |
|
1323 { |
|
1324 nsresult rv; |
|
1325 |
|
1326 NS_IF_ADDREF(gNativeAppSupport = native); |
|
1327 |
|
1328 // Inform the chrome registry about OS accessibility |
|
1329 nsCOMPtr<nsIToolkitChromeRegistry> cr = |
|
1330 mozilla::services::GetToolkitChromeRegistryService(); |
|
1331 |
|
1332 if (cr) |
|
1333 cr->CheckForOSAccessibility(); |
|
1334 |
|
1335 nsCOMPtr<nsIWindowCreator> creator (do_GetService(NS_APPSTARTUP_CONTRACTID)); |
|
1336 if (!creator) return NS_ERROR_UNEXPECTED; |
|
1337 |
|
1338 nsCOMPtr<nsIWindowWatcher> wwatch |
|
1339 (do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv)); |
|
1340 NS_ENSURE_SUCCESS(rv, rv); |
|
1341 |
|
1342 return wwatch->SetWindowCreator(creator); |
|
1343 } |
|
1344 |
|
1345 /* static */ nsresult |
|
1346 ScopedXPCOMStartup::CreateAppSupport(nsISupports* aOuter, REFNSIID aIID, void** aResult) |
|
1347 { |
|
1348 if (aOuter) |
|
1349 return NS_ERROR_NO_AGGREGATION; |
|
1350 |
|
1351 if (!gNativeAppSupport) |
|
1352 return NS_ERROR_NOT_INITIALIZED; |
|
1353 |
|
1354 return gNativeAppSupport->QueryInterface(aIID, aResult); |
|
1355 } |
|
1356 |
|
1357 nsINativeAppSupport* ScopedXPCOMStartup::gNativeAppSupport; |
|
1358 |
|
1359 /** |
|
1360 * A helper class which calls NS_LogInit/NS_LogTerm in its scope. |
|
1361 */ |
|
1362 class ScopedLogging |
|
1363 { |
|
1364 public: |
|
1365 ScopedLogging() { NS_LogInit(); } |
|
1366 ~ScopedLogging() { NS_LogTerm(); } |
|
1367 }; |
|
1368 |
|
1369 static void DumpArbitraryHelp() |
|
1370 { |
|
1371 nsresult rv; |
|
1372 |
|
1373 ScopedLogging log; |
|
1374 |
|
1375 { |
|
1376 ScopedXPCOMStartup xpcom; |
|
1377 xpcom.Initialize(); |
|
1378 |
|
1379 nsCOMPtr<nsICommandLineRunner> cmdline |
|
1380 (do_CreateInstance("@mozilla.org/toolkit/command-line;1")); |
|
1381 if (!cmdline) |
|
1382 return; |
|
1383 |
|
1384 nsCString text; |
|
1385 rv = cmdline->GetHelpText(text); |
|
1386 if (NS_SUCCEEDED(rv)) |
|
1387 printf("%s", text.get()); |
|
1388 } |
|
1389 } |
|
1390 |
|
1391 // English text needs to go into a dtd file. |
|
1392 // But when this is called we have no components etc. These strings must either be |
|
1393 // here, or in a native resource file. |
|
1394 static void |
|
1395 DumpHelp() |
|
1396 { |
|
1397 printf("Usage: %s [ options ... ] [URL]\n" |
|
1398 " where options include:\n\n", gArgv[0]); |
|
1399 |
|
1400 #ifdef MOZ_X11 |
|
1401 printf("X11 options\n" |
|
1402 " --display=DISPLAY X display to use\n" |
|
1403 " --sync Make X calls synchronous\n"); |
|
1404 #endif |
|
1405 #ifdef XP_UNIX |
|
1406 printf(" --g-fatal-warnings Make all warnings fatal\n" |
|
1407 "\n%s options\n", gAppData->name); |
|
1408 #endif |
|
1409 |
|
1410 printf(" -h or -help Print this message.\n" |
|
1411 " -v or -version Print %s version.\n" |
|
1412 " -P <profile> Start with <profile>.\n" |
|
1413 " -migration Start with migration wizard.\n" |
|
1414 " -ProfileManager Start with ProfileManager.\n" |
|
1415 " -no-remote (default) Do not accept or send remote commands; implies -new-instance.\n" |
|
1416 " -allow-remote Accept and send remote commands.\n" |
|
1417 " -new-instance Open new instance, not a new window in running instance.\n" |
|
1418 " -UILocale <locale> Start with <locale> resources as UI Locale.\n" |
|
1419 " -safe-mode Disables extensions and themes for this session.\n", gAppData->name); |
|
1420 |
|
1421 #if defined(XP_WIN) |
|
1422 printf(" -console Start %s with a debugging console.\n", gAppData->name); |
|
1423 #endif |
|
1424 |
|
1425 // this works, but only after the components have registered. so if you drop in a new command line handler, -help |
|
1426 // won't not until the second run. |
|
1427 // out of the bug, because we ship a component.reg file, it works correctly. |
|
1428 DumpArbitraryHelp(); |
|
1429 } |
|
1430 |
|
1431 #if defined(DEBUG) && defined(XP_WIN) |
|
1432 #ifdef DEBUG_warren |
|
1433 #define _CRTDBG_MAP_ALLOC |
|
1434 #endif |
|
1435 // Set a CRT ReportHook function to capture and format MSCRT |
|
1436 // warnings, errors and assertions. |
|
1437 // See http://msdn.microsoft.com/en-US/library/74kabxyx(v=VS.80).aspx |
|
1438 #include <stdio.h> |
|
1439 #include <crtdbg.h> |
|
1440 #include "mozilla/mozalloc_abort.h" |
|
1441 static int MSCRTReportHook( int aReportType, char *aMessage, int *oReturnValue) |
|
1442 { |
|
1443 *oReturnValue = 0; // continue execution |
|
1444 |
|
1445 // Do not use fprintf or other functions which may allocate |
|
1446 // memory from the heap which may be corrupted. Instead, |
|
1447 // use fputs to output the leading portion of the message |
|
1448 // and use mozalloc_abort to emit the remainder of the |
|
1449 // message. |
|
1450 |
|
1451 switch(aReportType) { |
|
1452 case 0: |
|
1453 fputs("\nWARNING: CRT WARNING", stderr); |
|
1454 fputs(aMessage, stderr); |
|
1455 fputs("\n", stderr); |
|
1456 break; |
|
1457 case 1: |
|
1458 fputs("\n###!!! ABORT: CRT ERROR ", stderr); |
|
1459 mozalloc_abort(aMessage); |
|
1460 break; |
|
1461 case 2: |
|
1462 fputs("\n###!!! ABORT: CRT ASSERT ", stderr); |
|
1463 mozalloc_abort(aMessage); |
|
1464 break; |
|
1465 } |
|
1466 |
|
1467 // do not invoke the debugger |
|
1468 return 1; |
|
1469 } |
|
1470 |
|
1471 #endif |
|
1472 |
|
1473 static inline void |
|
1474 DumpVersion() |
|
1475 { |
|
1476 if (gAppData->vendor) |
|
1477 printf("%s ", gAppData->vendor); |
|
1478 printf("%s %s", gAppData->name, gAppData->version); |
|
1479 if (gAppData->copyright) |
|
1480 printf(", %s", gAppData->copyright); |
|
1481 printf("\n"); |
|
1482 } |
|
1483 |
|
1484 #ifdef MOZ_ENABLE_XREMOTE |
|
1485 // use int here instead of a PR type since it will be returned |
|
1486 // from main - just to keep types consistent |
|
1487 static int |
|
1488 HandleRemoteArgument(const char* remote, const char* aDesktopStartupID) |
|
1489 { |
|
1490 nsresult rv; |
|
1491 ArgResult ar; |
|
1492 |
|
1493 const char *profile = 0; |
|
1494 nsAutoCString program(gAppData->name); |
|
1495 ToLowerCase(program); |
|
1496 const char *username = getenv("LOGNAME"); |
|
1497 |
|
1498 ar = CheckArg("p", false, &profile); |
|
1499 if (ar == ARG_BAD) { |
|
1500 PR_fprintf(PR_STDERR, "Error: argument -p requires a profile name\n"); |
|
1501 return 1; |
|
1502 } |
|
1503 |
|
1504 const char *temp = nullptr; |
|
1505 ar = CheckArg("a", false, &temp); |
|
1506 if (ar == ARG_BAD) { |
|
1507 PR_fprintf(PR_STDERR, "Error: argument -a requires an application name\n"); |
|
1508 return 1; |
|
1509 } else if (ar == ARG_FOUND) { |
|
1510 program.Assign(temp); |
|
1511 } |
|
1512 |
|
1513 ar = CheckArg("u", false, &username); |
|
1514 if (ar == ARG_BAD) { |
|
1515 PR_fprintf(PR_STDERR, "Error: argument -u requires a username\n"); |
|
1516 return 1; |
|
1517 } |
|
1518 |
|
1519 XRemoteClient client; |
|
1520 rv = client.Init(); |
|
1521 if (NS_FAILED(rv)) { |
|
1522 PR_fprintf(PR_STDERR, "Error: Failed to connect to X server.\n"); |
|
1523 return 1; |
|
1524 } |
|
1525 |
|
1526 nsXPIDLCString response; |
|
1527 bool success = false; |
|
1528 rv = client.SendCommand(program.get(), username, profile, remote, |
|
1529 aDesktopStartupID, getter_Copies(response), &success); |
|
1530 // did the command fail? |
|
1531 if (NS_FAILED(rv)) { |
|
1532 PR_fprintf(PR_STDERR, "Error: Failed to send command: %s\n", |
|
1533 response ? response.get() : "No response included"); |
|
1534 return 1; |
|
1535 } |
|
1536 |
|
1537 if (!success) { |
|
1538 PR_fprintf(PR_STDERR, "Error: No running window found\n"); |
|
1539 return 2; |
|
1540 } |
|
1541 |
|
1542 return 0; |
|
1543 } |
|
1544 |
|
1545 static RemoteResult |
|
1546 RemoteCommandLine(const char* aDesktopStartupID) |
|
1547 { |
|
1548 nsresult rv; |
|
1549 ArgResult ar; |
|
1550 |
|
1551 nsAutoCString program(gAppData->name); |
|
1552 ToLowerCase(program); |
|
1553 const char *username = getenv("LOGNAME"); |
|
1554 |
|
1555 const char *temp = nullptr; |
|
1556 ar = CheckArg("a", true, &temp); |
|
1557 if (ar == ARG_BAD) { |
|
1558 PR_fprintf(PR_STDERR, "Error: argument -a requires an application name\n"); |
|
1559 return REMOTE_ARG_BAD; |
|
1560 } else if (ar == ARG_FOUND) { |
|
1561 program.Assign(temp); |
|
1562 } |
|
1563 |
|
1564 ar = CheckArg("u", true, &username); |
|
1565 if (ar == ARG_BAD) { |
|
1566 PR_fprintf(PR_STDERR, "Error: argument -u requires a username\n"); |
|
1567 return REMOTE_ARG_BAD; |
|
1568 } |
|
1569 |
|
1570 XRemoteClient client; |
|
1571 rv = client.Init(); |
|
1572 if (NS_FAILED(rv)) |
|
1573 return REMOTE_NOT_FOUND; |
|
1574 |
|
1575 nsXPIDLCString response; |
|
1576 bool success = false; |
|
1577 rv = client.SendCommandLine(program.get(), username, nullptr, |
|
1578 gArgc, gArgv, aDesktopStartupID, |
|
1579 getter_Copies(response), &success); |
|
1580 // did the command fail? |
|
1581 if (NS_FAILED(rv) || !success) |
|
1582 return REMOTE_NOT_FOUND; |
|
1583 |
|
1584 return REMOTE_FOUND; |
|
1585 } |
|
1586 #endif // MOZ_ENABLE_XREMOTE |
|
1587 |
|
1588 void |
|
1589 XRE_InitOmnijar(nsIFile* greOmni, nsIFile* appOmni) |
|
1590 { |
|
1591 mozilla::Omnijar::Init(greOmni, appOmni); |
|
1592 } |
|
1593 |
|
1594 nsresult |
|
1595 XRE_GetBinaryPath(const char* argv0, nsIFile* *aResult) |
|
1596 { |
|
1597 return mozilla::BinaryPath::GetFile(argv0, aResult); |
|
1598 } |
|
1599 |
|
1600 #ifdef XP_WIN |
|
1601 #include "nsWindowsRestart.cpp" |
|
1602 #include <shellapi.h> |
|
1603 |
|
1604 typedef BOOL (WINAPI* SetProcessDEPPolicyFunc)(DWORD dwFlags); |
|
1605 #endif |
|
1606 |
|
1607 // If aBlankCommandLine is true, then the application will be launched with a |
|
1608 // blank command line instead of being launched with the same command line that |
|
1609 // it was initially started with. |
|
1610 static nsresult LaunchChild(nsINativeAppSupport* aNative, |
|
1611 bool aBlankCommandLine = false) |
|
1612 { |
|
1613 aNative->Quit(); // release DDE mutex, if we're holding it |
|
1614 |
|
1615 // Restart this process by exec'ing it into the current process |
|
1616 // if supported by the platform. Otherwise, use NSPR. |
|
1617 |
|
1618 #ifdef MOZ_JPROF |
|
1619 // make sure JPROF doesn't think we're E10s |
|
1620 unsetenv("JPROF_SLAVE"); |
|
1621 #endif |
|
1622 |
|
1623 if (aBlankCommandLine) { |
|
1624 #if defined(MOZ_WIDGET_QT) |
|
1625 // Remove only arguments not given to Qt |
|
1626 gRestartArgc = gQtOnlyArgc; |
|
1627 gRestartArgv = gQtOnlyArgv; |
|
1628 #else |
|
1629 gRestartArgc = 1; |
|
1630 gRestartArgv[gRestartArgc] = nullptr; |
|
1631 #endif |
|
1632 } |
|
1633 |
|
1634 SaveToEnv("MOZ_LAUNCHED_CHILD=1"); |
|
1635 |
|
1636 #if defined(MOZ_WIDGET_ANDROID) |
|
1637 mozilla::widget::android::GeckoAppShell::ScheduleRestart(); |
|
1638 #else |
|
1639 #if defined(XP_MACOSX) |
|
1640 CommandLineServiceMac::SetupMacCommandLine(gRestartArgc, gRestartArgv, true); |
|
1641 uint32_t restartMode = 0; |
|
1642 restartMode = gRestartMode; |
|
1643 LaunchChildMac(gRestartArgc, gRestartArgv, restartMode); |
|
1644 #else |
|
1645 nsCOMPtr<nsIFile> lf; |
|
1646 nsresult rv = XRE_GetBinaryPath(gArgv[0], getter_AddRefs(lf)); |
|
1647 if (NS_FAILED(rv)) |
|
1648 return rv; |
|
1649 |
|
1650 #if defined(XP_WIN) |
|
1651 nsAutoString exePath; |
|
1652 rv = lf->GetPath(exePath); |
|
1653 if (NS_FAILED(rv)) |
|
1654 return rv; |
|
1655 |
|
1656 if (!WinLaunchChild(exePath.get(), gRestartArgc, gRestartArgv)) |
|
1657 return NS_ERROR_FAILURE; |
|
1658 |
|
1659 #else |
|
1660 nsAutoCString exePath; |
|
1661 rv = lf->GetNativePath(exePath); |
|
1662 if (NS_FAILED(rv)) |
|
1663 return rv; |
|
1664 |
|
1665 #if defined(XP_UNIX) |
|
1666 if (execv(exePath.get(), gRestartArgv) == -1) |
|
1667 return NS_ERROR_FAILURE; |
|
1668 #else |
|
1669 PRProcess* process = PR_CreateProcess(exePath.get(), gRestartArgv, |
|
1670 nullptr, nullptr); |
|
1671 if (!process) return NS_ERROR_FAILURE; |
|
1672 |
|
1673 int32_t exitCode; |
|
1674 PRStatus failed = PR_WaitProcess(process, &exitCode); |
|
1675 if (failed || exitCode) |
|
1676 return NS_ERROR_FAILURE; |
|
1677 #endif // XP_UNIX |
|
1678 #endif // WP_WIN |
|
1679 #endif // WP_MACOSX |
|
1680 #endif // MOZ_WIDGET_ANDROID |
|
1681 |
|
1682 return NS_ERROR_LAUNCHED_CHILD_PROCESS; |
|
1683 } |
|
1684 |
|
1685 static const char kProfileProperties[] = |
|
1686 "chrome://mozapps/locale/profile/profileSelection.properties"; |
|
1687 |
|
1688 static nsresult |
|
1689 ProfileLockedDialog(nsIFile* aProfileDir, nsIFile* aProfileLocalDir, |
|
1690 nsIProfileUnlocker* aUnlocker, |
|
1691 nsINativeAppSupport* aNative, nsIProfileLock* *aResult) |
|
1692 { |
|
1693 nsresult rv; |
|
1694 |
|
1695 ScopedXPCOMStartup xpcom; |
|
1696 rv = xpcom.Initialize(); |
|
1697 NS_ENSURE_SUCCESS(rv, rv); |
|
1698 |
|
1699 mozilla::Telemetry::WriteFailedProfileLock(aProfileDir); |
|
1700 |
|
1701 rv = xpcom.SetWindowCreator(aNative); |
|
1702 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); |
|
1703 |
|
1704 { //extra scoping is needed so we release these components before xpcom shutdown |
|
1705 nsCOMPtr<nsIStringBundleService> sbs = |
|
1706 mozilla::services::GetStringBundleService(); |
|
1707 NS_ENSURE_TRUE(sbs, NS_ERROR_FAILURE); |
|
1708 |
|
1709 nsCOMPtr<nsIStringBundle> sb; |
|
1710 sbs->CreateBundle(kProfileProperties, getter_AddRefs(sb)); |
|
1711 NS_ENSURE_TRUE_LOG(sbs, NS_ERROR_FAILURE); |
|
1712 |
|
1713 NS_ConvertUTF8toUTF16 appName(gAppData->name); |
|
1714 const char16_t* params[] = {appName.get(), appName.get()}; |
|
1715 |
|
1716 nsXPIDLString killMessage; |
|
1717 #ifndef XP_MACOSX |
|
1718 static const char16_t kRestartNoUnlocker[] = {'r','e','s','t','a','r','t','M','e','s','s','a','g','e','N','o','U','n','l','o','c','k','e','r','\0'}; // "restartMessageNoUnlocker" |
|
1719 static const char16_t kRestartUnlocker[] = {'r','e','s','t','a','r','t','M','e','s','s','a','g','e','U','n','l','o','c','k','e','r','\0'}; // "restartMessageUnlocker" |
|
1720 #else |
|
1721 static const char16_t kRestartNoUnlocker[] = {'r','e','s','t','a','r','t','M','e','s','s','a','g','e','N','o','U','n','l','o','c','k','e','r','M','a','c','\0'}; // "restartMessageNoUnlockerMac" |
|
1722 static const char16_t kRestartUnlocker[] = {'r','e','s','t','a','r','t','M','e','s','s','a','g','e','U','n','l','o','c','k','e','r','M','a','c','\0'}; // "restartMessageUnlockerMac" |
|
1723 #endif |
|
1724 |
|
1725 sb->FormatStringFromName(aUnlocker ? kRestartUnlocker : kRestartNoUnlocker, |
|
1726 params, 2, getter_Copies(killMessage)); |
|
1727 |
|
1728 nsXPIDLString killTitle; |
|
1729 sb->FormatStringFromName(MOZ_UTF16("restartTitle"), |
|
1730 params, 1, getter_Copies(killTitle)); |
|
1731 |
|
1732 if (!killMessage || !killTitle) |
|
1733 return NS_ERROR_FAILURE; |
|
1734 |
|
1735 nsCOMPtr<nsIPromptService> ps |
|
1736 (do_GetService(NS_PROMPTSERVICE_CONTRACTID)); |
|
1737 NS_ENSURE_TRUE(ps, NS_ERROR_FAILURE); |
|
1738 |
|
1739 if (aUnlocker) { |
|
1740 int32_t button; |
|
1741 #ifdef MOZ_WIDGET_ANDROID |
|
1742 mozilla::widget::android::GeckoAppShell::KillAnyZombies(); |
|
1743 button = 1; |
|
1744 #else |
|
1745 const uint32_t flags = |
|
1746 (nsIPromptService::BUTTON_TITLE_CANCEL * |
|
1747 nsIPromptService::BUTTON_POS_0) + |
|
1748 (nsIPromptService::BUTTON_TITLE_IS_STRING * |
|
1749 nsIPromptService::BUTTON_POS_1) + |
|
1750 nsIPromptService::BUTTON_POS_1_DEFAULT; |
|
1751 |
|
1752 bool checkState = false; |
|
1753 rv = ps->ConfirmEx(nullptr, killTitle, killMessage, flags, |
|
1754 killTitle, nullptr, nullptr, nullptr, |
|
1755 &checkState, &button); |
|
1756 NS_ENSURE_SUCCESS_LOG(rv, rv); |
|
1757 #endif |
|
1758 |
|
1759 if (button == 1) { |
|
1760 rv = aUnlocker->Unlock(nsIProfileUnlocker::FORCE_QUIT); |
|
1761 if (NS_FAILED(rv)) |
|
1762 return rv; |
|
1763 |
|
1764 return NS_LockProfilePath(aProfileDir, aProfileLocalDir, |
|
1765 nullptr, aResult); |
|
1766 } |
|
1767 } else { |
|
1768 #ifdef MOZ_WIDGET_ANDROID |
|
1769 if (mozilla::widget::android::GeckoAppShell::UnlockProfile()) { |
|
1770 return NS_LockProfilePath(aProfileDir, aProfileLocalDir, |
|
1771 nullptr, aResult); |
|
1772 } |
|
1773 #else |
|
1774 rv = ps->Alert(nullptr, killTitle, killMessage); |
|
1775 NS_ENSURE_SUCCESS_LOG(rv, rv); |
|
1776 #endif |
|
1777 } |
|
1778 |
|
1779 return NS_ERROR_ABORT; |
|
1780 } |
|
1781 } |
|
1782 |
|
1783 |
|
1784 static nsresult |
|
1785 ProfileMissingDialog(nsINativeAppSupport* aNative) |
|
1786 { |
|
1787 nsresult rv; |
|
1788 |
|
1789 ScopedXPCOMStartup xpcom; |
|
1790 rv = xpcom.Initialize(); |
|
1791 NS_ENSURE_SUCCESS(rv, rv); |
|
1792 |
|
1793 rv = xpcom.SetWindowCreator(aNative); |
|
1794 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); |
|
1795 |
|
1796 { //extra scoping is needed so we release these components before xpcom shutdown |
|
1797 nsCOMPtr<nsIStringBundleService> sbs = |
|
1798 mozilla::services::GetStringBundleService(); |
|
1799 NS_ENSURE_TRUE(sbs, NS_ERROR_FAILURE); |
|
1800 |
|
1801 nsCOMPtr<nsIStringBundle> sb; |
|
1802 sbs->CreateBundle(kProfileProperties, getter_AddRefs(sb)); |
|
1803 NS_ENSURE_TRUE_LOG(sbs, NS_ERROR_FAILURE); |
|
1804 |
|
1805 NS_ConvertUTF8toUTF16 appName(gAppData->name); |
|
1806 const char16_t* params[] = {appName.get(), appName.get()}; |
|
1807 |
|
1808 nsXPIDLString missingMessage; |
|
1809 |
|
1810 // profileMissing |
|
1811 static const char16_t kMissing[] = {'p','r','o','f','i','l','e','M','i','s','s','i','n','g','\0'}; |
|
1812 sb->FormatStringFromName(kMissing, params, 2, getter_Copies(missingMessage)); |
|
1813 |
|
1814 nsXPIDLString missingTitle; |
|
1815 sb->FormatStringFromName(MOZ_UTF16("profileMissingTitle"), |
|
1816 params, 1, getter_Copies(missingTitle)); |
|
1817 |
|
1818 if (missingMessage && missingTitle) { |
|
1819 nsCOMPtr<nsIPromptService> ps |
|
1820 (do_GetService(NS_PROMPTSERVICE_CONTRACTID)); |
|
1821 NS_ENSURE_TRUE(ps, NS_ERROR_FAILURE); |
|
1822 |
|
1823 ps->Alert(nullptr, missingTitle, missingMessage); |
|
1824 } |
|
1825 |
|
1826 return NS_ERROR_ABORT; |
|
1827 } |
|
1828 } |
|
1829 |
|
1830 static nsresult |
|
1831 ProfileLockedDialog(nsIToolkitProfile* aProfile, nsIProfileUnlocker* aUnlocker, |
|
1832 nsINativeAppSupport* aNative, nsIProfileLock* *aResult) |
|
1833 { |
|
1834 nsCOMPtr<nsIFile> profileDir; |
|
1835 nsresult rv = aProfile->GetRootDir(getter_AddRefs(profileDir)); |
|
1836 if (NS_FAILED(rv)) return rv; |
|
1837 |
|
1838 bool exists; |
|
1839 profileDir->Exists(&exists); |
|
1840 if (!exists) { |
|
1841 return ProfileMissingDialog(aNative); |
|
1842 } |
|
1843 |
|
1844 nsCOMPtr<nsIFile> profileLocalDir; |
|
1845 rv = aProfile->GetLocalDir(getter_AddRefs(profileLocalDir)); |
|
1846 if (NS_FAILED(rv)) return rv; |
|
1847 |
|
1848 return ProfileLockedDialog(profileDir, profileLocalDir, aUnlocker, aNative, |
|
1849 aResult); |
|
1850 } |
|
1851 |
|
1852 static const char kProfileManagerURL[] = |
|
1853 "chrome://mozapps/content/profile/profileSelection.xul"; |
|
1854 |
|
1855 static nsresult |
|
1856 ShowProfileManager(nsIToolkitProfileService* aProfileSvc, |
|
1857 nsINativeAppSupport* aNative) |
|
1858 { |
|
1859 if (!CanShowProfileManager()) { |
|
1860 return NS_ERROR_NOT_IMPLEMENTED; |
|
1861 } |
|
1862 |
|
1863 nsresult rv; |
|
1864 |
|
1865 nsCOMPtr<nsIFile> profD, profLD; |
|
1866 char16_t* profileNamePtr; |
|
1867 nsAutoCString profileName; |
|
1868 |
|
1869 { |
|
1870 ScopedXPCOMStartup xpcom; |
|
1871 rv = xpcom.Initialize(); |
|
1872 NS_ENSURE_SUCCESS(rv, rv); |
|
1873 |
|
1874 rv = xpcom.SetWindowCreator(aNative); |
|
1875 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); |
|
1876 |
|
1877 #ifdef XP_MACOSX |
|
1878 CommandLineServiceMac::SetupMacCommandLine(gRestartArgc, gRestartArgv, true); |
|
1879 #endif |
|
1880 |
|
1881 #ifdef XP_WIN |
|
1882 // we don't have to wait here because profile manager window will pump |
|
1883 // and DDE message will be handled |
|
1884 ProcessDDE(aNative, false); |
|
1885 #endif |
|
1886 |
|
1887 { //extra scoping is needed so we release these components before xpcom shutdown |
|
1888 nsCOMPtr<nsIWindowWatcher> windowWatcher |
|
1889 (do_GetService(NS_WINDOWWATCHER_CONTRACTID)); |
|
1890 nsCOMPtr<nsIDialogParamBlock> ioParamBlock |
|
1891 (do_CreateInstance(NS_DIALOGPARAMBLOCK_CONTRACTID)); |
|
1892 nsCOMPtr<nsIMutableArray> dlgArray (do_CreateInstance(NS_ARRAY_CONTRACTID)); |
|
1893 NS_ENSURE_TRUE(windowWatcher && ioParamBlock && dlgArray, NS_ERROR_FAILURE); |
|
1894 |
|
1895 ioParamBlock->SetObjects(dlgArray); |
|
1896 |
|
1897 nsCOMPtr<nsIAppStartup> appStartup |
|
1898 (do_GetService(NS_APPSTARTUP_CONTRACTID)); |
|
1899 NS_ENSURE_TRUE(appStartup, NS_ERROR_FAILURE); |
|
1900 |
|
1901 nsCOMPtr<nsIDOMWindow> newWindow; |
|
1902 rv = windowWatcher->OpenWindow(nullptr, |
|
1903 kProfileManagerURL, |
|
1904 "_blank", |
|
1905 "centerscreen,chrome,modal,titlebar", |
|
1906 ioParamBlock, |
|
1907 getter_AddRefs(newWindow)); |
|
1908 |
|
1909 NS_ENSURE_SUCCESS_LOG(rv, rv); |
|
1910 |
|
1911 aProfileSvc->Flush(); |
|
1912 |
|
1913 int32_t dialogConfirmed; |
|
1914 rv = ioParamBlock->GetInt(0, &dialogConfirmed); |
|
1915 if (NS_FAILED(rv) || dialogConfirmed == 0) return NS_ERROR_ABORT; |
|
1916 |
|
1917 nsCOMPtr<nsIProfileLock> lock; |
|
1918 rv = dlgArray->QueryElementAt(0, NS_GET_IID(nsIProfileLock), |
|
1919 getter_AddRefs(lock)); |
|
1920 NS_ENSURE_SUCCESS_LOG(rv, rv); |
|
1921 |
|
1922 rv = lock->GetDirectory(getter_AddRefs(profD)); |
|
1923 NS_ENSURE_SUCCESS(rv, rv); |
|
1924 |
|
1925 rv = lock->GetLocalDirectory(getter_AddRefs(profLD)); |
|
1926 NS_ENSURE_SUCCESS(rv, rv); |
|
1927 |
|
1928 rv = ioParamBlock->GetString(0, &profileNamePtr); |
|
1929 NS_ENSURE_SUCCESS(rv, rv); |
|
1930 |
|
1931 CopyUTF16toUTF8(profileNamePtr, profileName); |
|
1932 NS_Free(profileNamePtr); |
|
1933 |
|
1934 lock->Unlock(); |
|
1935 } |
|
1936 } |
|
1937 |
|
1938 SaveFileToEnv("XRE_PROFILE_PATH", profD); |
|
1939 SaveFileToEnv("XRE_PROFILE_LOCAL_PATH", profLD); |
|
1940 SaveWordToEnv("XRE_PROFILE_NAME", profileName); |
|
1941 |
|
1942 bool offline = false; |
|
1943 aProfileSvc->GetStartOffline(&offline); |
|
1944 if (offline) { |
|
1945 SaveToEnv("XRE_START_OFFLINE=1"); |
|
1946 } |
|
1947 |
|
1948 return LaunchChild(aNative); |
|
1949 } |
|
1950 |
|
1951 static nsresult |
|
1952 GetCurrentProfileIsDefault(nsIToolkitProfileService* aProfileSvc, |
|
1953 nsIFile* aCurrentProfileRoot, bool *aResult) |
|
1954 { |
|
1955 nsresult rv; |
|
1956 // Check that the profile to reset is the default since reset and the associated migration are |
|
1957 // only supported in that case. |
|
1958 nsCOMPtr<nsIToolkitProfile> selectedProfile; |
|
1959 nsCOMPtr<nsIFile> selectedProfileRoot; |
|
1960 rv = aProfileSvc->GetSelectedProfile(getter_AddRefs(selectedProfile)); |
|
1961 NS_ENSURE_SUCCESS(rv, rv); |
|
1962 |
|
1963 rv = selectedProfile->GetRootDir(getter_AddRefs(selectedProfileRoot)); |
|
1964 NS_ENSURE_SUCCESS(rv, rv); |
|
1965 |
|
1966 bool currentIsSelected; |
|
1967 rv = aCurrentProfileRoot->Equals(selectedProfileRoot, ¤tIsSelected); |
|
1968 |
|
1969 *aResult = currentIsSelected; |
|
1970 return rv; |
|
1971 } |
|
1972 |
|
1973 /** |
|
1974 * Set the currently running profile as the default/selected one. |
|
1975 * |
|
1976 * @param aCurrentProfileRoot The root directory of the current profile. |
|
1977 * @return an error if aCurrentProfileRoot is not found or the profile could not |
|
1978 * be set as the default. |
|
1979 */ |
|
1980 static nsresult |
|
1981 SetCurrentProfileAsDefault(nsIToolkitProfileService* aProfileSvc, |
|
1982 nsIFile* aCurrentProfileRoot) |
|
1983 { |
|
1984 NS_ENSURE_ARG_POINTER(aProfileSvc); |
|
1985 |
|
1986 nsCOMPtr<nsISimpleEnumerator> profiles; |
|
1987 nsresult rv = aProfileSvc->GetProfiles(getter_AddRefs(profiles)); |
|
1988 if (NS_FAILED(rv)) |
|
1989 return rv; |
|
1990 |
|
1991 bool foundMatchingProfile = false; |
|
1992 nsCOMPtr<nsISupports> supports; |
|
1993 rv = profiles->GetNext(getter_AddRefs(supports)); |
|
1994 while (NS_SUCCEEDED(rv)) { |
|
1995 nsCOMPtr<nsIToolkitProfile> profile = do_QueryInterface(supports); |
|
1996 nsCOMPtr<nsIFile> profileRoot; |
|
1997 profile->GetRootDir(getter_AddRefs(profileRoot)); |
|
1998 profileRoot->Equals(aCurrentProfileRoot, &foundMatchingProfile); |
|
1999 if (foundMatchingProfile && profile) { |
|
2000 rv = aProfileSvc->SetSelectedProfile(profile); |
|
2001 if (NS_SUCCEEDED(rv)) |
|
2002 rv = aProfileSvc->Flush(); |
|
2003 return rv; |
|
2004 } |
|
2005 rv = profiles->GetNext(getter_AddRefs(supports)); |
|
2006 } |
|
2007 return rv; |
|
2008 } |
|
2009 |
|
2010 static bool gDoMigration = false; |
|
2011 static bool gDoProfileReset = false; |
|
2012 |
|
2013 // Pick a profile. We need to end up with a profile lock. |
|
2014 // |
|
2015 // 1) check for -profile <path> |
|
2016 // 2) check for -P <name> |
|
2017 // 3) check for -ProfileManager |
|
2018 // 4) use the default profile, if there is one |
|
2019 // 5) if there are *no* profiles, set up profile-migration |
|
2020 // 6) display the profile-manager UI |
|
2021 static nsresult |
|
2022 SelectProfile(nsIProfileLock* *aResult, nsIToolkitProfileService* aProfileSvc, nsINativeAppSupport* aNative, |
|
2023 bool* aStartOffline, nsACString* aProfileName) |
|
2024 { |
|
2025 StartupTimeline::Record(StartupTimeline::SELECT_PROFILE); |
|
2026 |
|
2027 nsresult rv; |
|
2028 ArgResult ar; |
|
2029 const char* arg; |
|
2030 *aResult = nullptr; |
|
2031 *aStartOffline = false; |
|
2032 |
|
2033 ar = CheckArg("offline", true); |
|
2034 if (ar == ARG_BAD) { |
|
2035 PR_fprintf(PR_STDERR, "Error: argument -offline is invalid when argument -osint is specified\n"); |
|
2036 return NS_ERROR_FAILURE; |
|
2037 } |
|
2038 |
|
2039 if (ar || EnvHasValue("XRE_START_OFFLINE")) |
|
2040 *aStartOffline = true; |
|
2041 |
|
2042 if (EnvHasValue("MOZ_RESET_PROFILE_RESTART")) { |
|
2043 gDoProfileReset = true; |
|
2044 gDoMigration = true; |
|
2045 SaveToEnv("MOZ_RESET_PROFILE_RESTART="); |
|
2046 } |
|
2047 |
|
2048 // reset-profile and migration args need to be checked before any profiles are chosen below. |
|
2049 ar = CheckArg("reset-profile", true); |
|
2050 if (ar == ARG_BAD) { |
|
2051 PR_fprintf(PR_STDERR, "Error: argument -reset-profile is invalid when argument -osint is specified\n"); |
|
2052 return NS_ERROR_FAILURE; |
|
2053 } else if (ar == ARG_FOUND) { |
|
2054 gDoProfileReset = true; |
|
2055 } |
|
2056 |
|
2057 ar = CheckArg("migration", true); |
|
2058 if (ar == ARG_BAD) { |
|
2059 PR_fprintf(PR_STDERR, "Error: argument -migration is invalid when argument -osint is specified\n"); |
|
2060 return NS_ERROR_FAILURE; |
|
2061 } else if (ar == ARG_FOUND) { |
|
2062 gDoMigration = true; |
|
2063 } |
|
2064 |
|
2065 nsCOMPtr<nsIFile> lf = GetFileFromEnv("XRE_PROFILE_PATH"); |
|
2066 if (lf) { |
|
2067 nsCOMPtr<nsIFile> localDir = |
|
2068 GetFileFromEnv("XRE_PROFILE_LOCAL_PATH"); |
|
2069 if (!localDir) { |
|
2070 localDir = lf; |
|
2071 } |
|
2072 |
|
2073 arg = PR_GetEnv("XRE_PROFILE_NAME"); |
|
2074 if (arg && *arg && aProfileName) |
|
2075 aProfileName->Assign(nsDependentCString(arg)); |
|
2076 |
|
2077 // Clear out flags that we handled (or should have handled!) last startup. |
|
2078 const char *dummy; |
|
2079 CheckArg("p", false, &dummy); |
|
2080 CheckArg("profile", false, &dummy); |
|
2081 CheckArg("profilemanager"); |
|
2082 |
|
2083 if (gDoProfileReset) { |
|
2084 // Check that the profile to reset is the default since reset and migration are only |
|
2085 // supported in that case. |
|
2086 bool currentIsSelected; |
|
2087 GetCurrentProfileIsDefault(aProfileSvc, lf, ¤tIsSelected); |
|
2088 if (!currentIsSelected) { |
|
2089 NS_WARNING("Profile reset is only supported for the default profile."); |
|
2090 gDoProfileReset = gDoMigration = false; |
|
2091 } |
|
2092 |
|
2093 // If we're resetting a profile, create a new one and use it to startup. |
|
2094 nsCOMPtr<nsIToolkitProfile> newProfile; |
|
2095 rv = CreateResetProfile(aProfileSvc, getter_AddRefs(newProfile)); |
|
2096 if (NS_SUCCEEDED(rv)) { |
|
2097 rv = newProfile->GetRootDir(getter_AddRefs(lf)); |
|
2098 NS_ENSURE_SUCCESS(rv, rv); |
|
2099 SaveFileToEnv("XRE_PROFILE_PATH", lf); |
|
2100 |
|
2101 rv = newProfile->GetLocalDir(getter_AddRefs(localDir)); |
|
2102 NS_ENSURE_SUCCESS(rv, rv); |
|
2103 SaveFileToEnv("XRE_PROFILE_LOCAL_PATH", localDir); |
|
2104 |
|
2105 rv = newProfile->GetName(*aProfileName); |
|
2106 if (NS_FAILED(rv)) |
|
2107 aProfileName->Truncate(0); |
|
2108 SaveWordToEnv("XRE_PROFILE_NAME", *aProfileName); |
|
2109 } else { |
|
2110 NS_WARNING("Profile reset failed."); |
|
2111 gDoProfileReset = false; |
|
2112 } |
|
2113 } |
|
2114 |
|
2115 return NS_LockProfilePath(lf, localDir, nullptr, aResult); |
|
2116 } |
|
2117 |
|
2118 ar = CheckArg("profile", true, &arg); |
|
2119 if (ar == ARG_BAD) { |
|
2120 PR_fprintf(PR_STDERR, "Error: argument -profile requires a path\n"); |
|
2121 return NS_ERROR_FAILURE; |
|
2122 } |
|
2123 if (ar) { |
|
2124 if (gDoProfileReset) { |
|
2125 NS_WARNING("Profile reset is only supported for the default profile."); |
|
2126 gDoProfileReset = false; |
|
2127 } |
|
2128 |
|
2129 nsCOMPtr<nsIFile> lf; |
|
2130 rv = XRE_GetFileFromPath(arg, getter_AddRefs(lf)); |
|
2131 NS_ENSURE_SUCCESS(rv, rv); |
|
2132 |
|
2133 nsCOMPtr<nsIProfileUnlocker> unlocker; |
|
2134 |
|
2135 // Check if the profile path exists and it's a directory. |
|
2136 bool exists; |
|
2137 lf->Exists(&exists); |
|
2138 if (!exists) { |
|
2139 rv = lf->Create(nsIFile::DIRECTORY_TYPE, 0700); |
|
2140 NS_ENSURE_SUCCESS(rv, rv); |
|
2141 } |
|
2142 |
|
2143 // If a profile path is specified directory on the command line, then |
|
2144 // assume that the temp directory is the same as the given directory. |
|
2145 rv = NS_LockProfilePath(lf, lf, getter_AddRefs(unlocker), aResult); |
|
2146 if (NS_SUCCEEDED(rv)) |
|
2147 return rv; |
|
2148 |
|
2149 return ProfileLockedDialog(lf, lf, unlocker, aNative, aResult); |
|
2150 } |
|
2151 |
|
2152 ar = CheckArg("createprofile", true, &arg); |
|
2153 if (ar == ARG_BAD) { |
|
2154 PR_fprintf(PR_STDERR, "Error: argument -createprofile requires a profile name\n"); |
|
2155 return NS_ERROR_FAILURE; |
|
2156 } |
|
2157 if (ar) { |
|
2158 nsCOMPtr<nsIToolkitProfile> profile; |
|
2159 |
|
2160 const char* delim = strchr(arg, ' '); |
|
2161 if (delim) { |
|
2162 nsCOMPtr<nsIFile> lf; |
|
2163 rv = NS_NewNativeLocalFile(nsDependentCString(delim + 1), |
|
2164 true, getter_AddRefs(lf)); |
|
2165 if (NS_FAILED(rv)) { |
|
2166 PR_fprintf(PR_STDERR, "Error: profile path not valid.\n"); |
|
2167 return rv; |
|
2168 } |
|
2169 |
|
2170 // As with -profile, assume that the given path will be used for the |
|
2171 // main profile directory. |
|
2172 rv = aProfileSvc->CreateProfile(lf, nsDependentCSubstring(arg, delim), |
|
2173 getter_AddRefs(profile)); |
|
2174 } else { |
|
2175 rv = aProfileSvc->CreateProfile(nullptr, nsDependentCString(arg), |
|
2176 getter_AddRefs(profile)); |
|
2177 } |
|
2178 // Some pathological arguments can make it this far |
|
2179 if (NS_FAILED(rv)) { |
|
2180 PR_fprintf(PR_STDERR, "Error creating profile.\n"); |
|
2181 return rv; |
|
2182 } |
|
2183 rv = NS_ERROR_ABORT; |
|
2184 aProfileSvc->Flush(); |
|
2185 |
|
2186 // XXXben need to ensure prefs.js exists here so the tinderboxes will |
|
2187 // not go orange. |
|
2188 nsCOMPtr<nsIFile> prefsJSFile; |
|
2189 profile->GetRootDir(getter_AddRefs(prefsJSFile)); |
|
2190 prefsJSFile->AppendNative(NS_LITERAL_CSTRING("prefs.js")); |
|
2191 nsAutoCString pathStr; |
|
2192 prefsJSFile->GetNativePath(pathStr); |
|
2193 PR_fprintf(PR_STDERR, "Success: created profile '%s' at '%s'\n", arg, pathStr.get()); |
|
2194 bool exists; |
|
2195 prefsJSFile->Exists(&exists); |
|
2196 if (!exists) |
|
2197 prefsJSFile->Create(nsIFile::NORMAL_FILE_TYPE, 0644); |
|
2198 // XXXdarin perhaps 0600 would be better? |
|
2199 |
|
2200 return rv; |
|
2201 } |
|
2202 |
|
2203 uint32_t count; |
|
2204 rv = aProfileSvc->GetProfileCount(&count); |
|
2205 NS_ENSURE_SUCCESS(rv, rv); |
|
2206 |
|
2207 ar = CheckArg("p", false, &arg); |
|
2208 if (ar == ARG_BAD) { |
|
2209 ar = CheckArg("osint"); |
|
2210 if (ar == ARG_FOUND) { |
|
2211 PR_fprintf(PR_STDERR, "Error: argument -p is invalid when argument -osint is specified\n"); |
|
2212 return NS_ERROR_FAILURE; |
|
2213 } |
|
2214 |
|
2215 if (CanShowProfileManager()) { |
|
2216 return ShowProfileManager(aProfileSvc, aNative); |
|
2217 } |
|
2218 } |
|
2219 if (ar) { |
|
2220 ar = CheckArg("osint"); |
|
2221 if (ar == ARG_FOUND) { |
|
2222 PR_fprintf(PR_STDERR, "Error: argument -p is invalid when argument -osint is specified\n"); |
|
2223 return NS_ERROR_FAILURE; |
|
2224 } |
|
2225 nsCOMPtr<nsIToolkitProfile> profile; |
|
2226 rv = aProfileSvc->GetProfileByName(nsDependentCString(arg), |
|
2227 getter_AddRefs(profile)); |
|
2228 if (NS_SUCCEEDED(rv)) { |
|
2229 if (gDoProfileReset) { |
|
2230 NS_WARNING("Profile reset is only supported for the default profile."); |
|
2231 gDoProfileReset = false; |
|
2232 } |
|
2233 |
|
2234 nsCOMPtr<nsIProfileUnlocker> unlocker; |
|
2235 rv = profile->Lock(getter_AddRefs(unlocker), aResult); |
|
2236 if (NS_SUCCEEDED(rv)) { |
|
2237 if (aProfileName) |
|
2238 aProfileName->Assign(nsDependentCString(arg)); |
|
2239 return NS_OK; |
|
2240 } |
|
2241 |
|
2242 return ProfileLockedDialog(profile, unlocker, aNative, aResult); |
|
2243 } |
|
2244 |
|
2245 if (CanShowProfileManager()) { |
|
2246 return ShowProfileManager(aProfileSvc, aNative); |
|
2247 } |
|
2248 } |
|
2249 |
|
2250 ar = CheckArg("profilemanager", true); |
|
2251 if (ar == ARG_BAD) { |
|
2252 PR_fprintf(PR_STDERR, "Error: argument -profilemanager is invalid when argument -osint is specified\n"); |
|
2253 return NS_ERROR_FAILURE; |
|
2254 } else if (ar == ARG_FOUND && CanShowProfileManager()) { |
|
2255 return ShowProfileManager(aProfileSvc, aNative); |
|
2256 } |
|
2257 |
|
2258 if (!count) { |
|
2259 gDoMigration = true; |
|
2260 gDoProfileReset = false; |
|
2261 |
|
2262 // create a default profile |
|
2263 nsCOMPtr<nsIToolkitProfile> profile; |
|
2264 nsresult rv = aProfileSvc->CreateProfile(nullptr, // choose a default dir for us |
|
2265 NS_LITERAL_CSTRING("default"), |
|
2266 getter_AddRefs(profile)); |
|
2267 if (NS_SUCCEEDED(rv)) { |
|
2268 aProfileSvc->Flush(); |
|
2269 rv = profile->Lock(nullptr, aResult); |
|
2270 if (NS_SUCCEEDED(rv)) { |
|
2271 if (aProfileName) |
|
2272 aProfileName->Assign(NS_LITERAL_CSTRING("default")); |
|
2273 return NS_OK; |
|
2274 } |
|
2275 } |
|
2276 } |
|
2277 |
|
2278 bool useDefault = true; |
|
2279 if (count > 1 && CanShowProfileManager()) { |
|
2280 aProfileSvc->GetStartWithLastProfile(&useDefault); |
|
2281 } |
|
2282 |
|
2283 if (useDefault) { |
|
2284 nsCOMPtr<nsIToolkitProfile> profile; |
|
2285 // GetSelectedProfile will auto-select the only profile if there's just one |
|
2286 aProfileSvc->GetSelectedProfile(getter_AddRefs(profile)); |
|
2287 if (profile) { |
|
2288 // If we're resetting a profile, create a new one and use it to startup. |
|
2289 if (gDoProfileReset) { |
|
2290 { |
|
2291 // Check that the source profile is not in use by temporarily acquiring its lock. |
|
2292 nsIProfileLock* tempProfileLock; |
|
2293 nsCOMPtr<nsIProfileUnlocker> unlocker; |
|
2294 rv = profile->Lock(getter_AddRefs(unlocker), &tempProfileLock); |
|
2295 if (NS_FAILED(rv)) |
|
2296 return ProfileLockedDialog(profile, unlocker, aNative, &tempProfileLock); |
|
2297 } |
|
2298 |
|
2299 nsCOMPtr<nsIToolkitProfile> newProfile; |
|
2300 rv = CreateResetProfile(aProfileSvc, getter_AddRefs(newProfile)); |
|
2301 if (NS_SUCCEEDED(rv)) |
|
2302 profile = newProfile; |
|
2303 else |
|
2304 gDoProfileReset = false; |
|
2305 } |
|
2306 |
|
2307 // If you close Firefox and very quickly reopen it, the old Firefox may |
|
2308 // still be closing down. Rather than immediately showing the |
|
2309 // "Firefox is running but is not responding" message, we spend a few |
|
2310 // seconds retrying first. |
|
2311 |
|
2312 static const int kLockRetrySeconds = 5; |
|
2313 static const int kLockRetrySleepMS = 100; |
|
2314 |
|
2315 nsCOMPtr<nsIProfileUnlocker> unlocker; |
|
2316 const TimeStamp start = TimeStamp::Now(); |
|
2317 do { |
|
2318 rv = profile->Lock(getter_AddRefs(unlocker), aResult); |
|
2319 if (NS_SUCCEEDED(rv)) { |
|
2320 StartupTimeline::Record(StartupTimeline::AFTER_PROFILE_LOCKED); |
|
2321 // Try to grab the profile name. |
|
2322 if (aProfileName) { |
|
2323 rv = profile->GetName(*aProfileName); |
|
2324 if (NS_FAILED(rv)) |
|
2325 aProfileName->Truncate(0); |
|
2326 } |
|
2327 return NS_OK; |
|
2328 } |
|
2329 PR_Sleep(kLockRetrySleepMS); |
|
2330 } while (TimeStamp::Now() - start < TimeDuration::FromSeconds(kLockRetrySeconds)); |
|
2331 |
|
2332 return ProfileLockedDialog(profile, unlocker, aNative, aResult); |
|
2333 } |
|
2334 } |
|
2335 |
|
2336 if (!CanShowProfileManager()) { |
|
2337 return NS_ERROR_FAILURE; |
|
2338 } |
|
2339 |
|
2340 return ShowProfileManager(aProfileSvc, aNative); |
|
2341 } |
|
2342 |
|
2343 /** |
|
2344 * Checks the compatibility.ini file to see if we have updated our application |
|
2345 * or otherwise invalidated our caches. If the application has been updated, |
|
2346 * we return false; otherwise, we return true. We also write the status |
|
2347 * of the caches (valid/invalid) into the return param aCachesOK. The aCachesOK |
|
2348 * is always invalid if the application has been updated. |
|
2349 */ |
|
2350 static bool |
|
2351 CheckCompatibility(nsIFile* aProfileDir, const nsCString& aVersion, |
|
2352 const nsCString& aOSABI, nsIFile* aXULRunnerDir, |
|
2353 nsIFile* aAppDir, nsIFile* aFlagFile, |
|
2354 bool* aCachesOK) |
|
2355 { |
|
2356 *aCachesOK = false; |
|
2357 nsCOMPtr<nsIFile> file; |
|
2358 aProfileDir->Clone(getter_AddRefs(file)); |
|
2359 if (!file) |
|
2360 return false; |
|
2361 file->AppendNative(FILE_COMPATIBILITY_INFO); |
|
2362 |
|
2363 nsINIParser parser; |
|
2364 nsresult rv = parser.Init(file); |
|
2365 if (NS_FAILED(rv)) |
|
2366 return false; |
|
2367 |
|
2368 nsAutoCString buf; |
|
2369 rv = parser.GetString("Compatibility", "LastVersion", buf); |
|
2370 if (NS_FAILED(rv) || !aVersion.Equals(buf)) |
|
2371 return false; |
|
2372 |
|
2373 rv = parser.GetString("Compatibility", "LastOSABI", buf); |
|
2374 if (NS_FAILED(rv) || !aOSABI.Equals(buf)) |
|
2375 return false; |
|
2376 |
|
2377 rv = parser.GetString("Compatibility", "LastPlatformDir", buf); |
|
2378 if (NS_FAILED(rv)) |
|
2379 return false; |
|
2380 |
|
2381 nsCOMPtr<nsIFile> lf; |
|
2382 rv = NS_NewNativeLocalFile(buf, false, |
|
2383 getter_AddRefs(lf)); |
|
2384 if (NS_FAILED(rv)) |
|
2385 return false; |
|
2386 |
|
2387 bool eq; |
|
2388 rv = lf->Equals(aXULRunnerDir, &eq); |
|
2389 if (NS_FAILED(rv) || !eq) |
|
2390 return false; |
|
2391 |
|
2392 if (aAppDir) { |
|
2393 rv = parser.GetString("Compatibility", "LastAppDir", buf); |
|
2394 if (NS_FAILED(rv)) |
|
2395 return false; |
|
2396 |
|
2397 rv = NS_NewNativeLocalFile(buf, false, |
|
2398 getter_AddRefs(lf)); |
|
2399 if (NS_FAILED(rv)) |
|
2400 return false; |
|
2401 |
|
2402 rv = lf->Equals(aAppDir, &eq); |
|
2403 if (NS_FAILED(rv) || !eq) |
|
2404 return false; |
|
2405 } |
|
2406 |
|
2407 // If we see this flag, caches are invalid. |
|
2408 rv = parser.GetString("Compatibility", "InvalidateCaches", buf); |
|
2409 *aCachesOK = (NS_FAILED(rv) || !buf.EqualsLiteral("1")); |
|
2410 |
|
2411 bool purgeCaches = false; |
|
2412 if (aFlagFile) { |
|
2413 aFlagFile->Exists(&purgeCaches); |
|
2414 } |
|
2415 |
|
2416 *aCachesOK = !purgeCaches && *aCachesOK; |
|
2417 return true; |
|
2418 } |
|
2419 |
|
2420 static void BuildVersion(nsCString &aBuf) |
|
2421 { |
|
2422 aBuf.Assign(gAppData->version); |
|
2423 aBuf.Append('_'); |
|
2424 aBuf.Append(gAppData->buildID); |
|
2425 aBuf.Append('/'); |
|
2426 aBuf.Append(gToolkitBuildID); |
|
2427 } |
|
2428 |
|
2429 static void |
|
2430 WriteVersion(nsIFile* aProfileDir, const nsCString& aVersion, |
|
2431 const nsCString& aOSABI, nsIFile* aXULRunnerDir, |
|
2432 nsIFile* aAppDir, bool invalidateCache) |
|
2433 { |
|
2434 nsCOMPtr<nsIFile> file; |
|
2435 aProfileDir->Clone(getter_AddRefs(file)); |
|
2436 if (!file) |
|
2437 return; |
|
2438 file->AppendNative(FILE_COMPATIBILITY_INFO); |
|
2439 |
|
2440 nsAutoCString platformDir; |
|
2441 aXULRunnerDir->GetNativePath(platformDir); |
|
2442 |
|
2443 nsAutoCString appDir; |
|
2444 if (aAppDir) |
|
2445 aAppDir->GetNativePath(appDir); |
|
2446 |
|
2447 PRFileDesc *fd = nullptr; |
|
2448 file->OpenNSPRFileDesc(PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, 0600, &fd); |
|
2449 if (!fd) { |
|
2450 NS_ERROR("could not create output stream"); |
|
2451 return; |
|
2452 } |
|
2453 |
|
2454 static const char kHeader[] = "[Compatibility]" NS_LINEBREAK |
|
2455 "LastVersion="; |
|
2456 |
|
2457 PR_Write(fd, kHeader, sizeof(kHeader) - 1); |
|
2458 PR_Write(fd, aVersion.get(), aVersion.Length()); |
|
2459 |
|
2460 static const char kOSABIHeader[] = NS_LINEBREAK "LastOSABI="; |
|
2461 PR_Write(fd, kOSABIHeader, sizeof(kOSABIHeader) - 1); |
|
2462 PR_Write(fd, aOSABI.get(), aOSABI.Length()); |
|
2463 |
|
2464 static const char kPlatformDirHeader[] = NS_LINEBREAK "LastPlatformDir="; |
|
2465 |
|
2466 PR_Write(fd, kPlatformDirHeader, sizeof(kPlatformDirHeader) - 1); |
|
2467 PR_Write(fd, platformDir.get(), platformDir.Length()); |
|
2468 |
|
2469 static const char kAppDirHeader[] = NS_LINEBREAK "LastAppDir="; |
|
2470 if (aAppDir) { |
|
2471 PR_Write(fd, kAppDirHeader, sizeof(kAppDirHeader) - 1); |
|
2472 PR_Write(fd, appDir.get(), appDir.Length()); |
|
2473 } |
|
2474 |
|
2475 static const char kInvalidationHeader[] = NS_LINEBREAK "InvalidateCaches=1"; |
|
2476 if (invalidateCache) |
|
2477 PR_Write(fd, kInvalidationHeader, sizeof(kInvalidationHeader) - 1); |
|
2478 |
|
2479 static const char kNL[] = NS_LINEBREAK; |
|
2480 PR_Write(fd, kNL, sizeof(kNL) - 1); |
|
2481 |
|
2482 PR_Close(fd); |
|
2483 } |
|
2484 |
|
2485 /** |
|
2486 * Returns true if the startup cache file was successfully removed. |
|
2487 * Returns false if file->Clone fails at any point (OOM) or if unable |
|
2488 * to remove the startup cache file. Note in particular the return value |
|
2489 * is unaffected by a failure to remove extensions.ini |
|
2490 */ |
|
2491 static bool |
|
2492 RemoveComponentRegistries(nsIFile* aProfileDir, nsIFile* aLocalProfileDir, |
|
2493 bool aRemoveEMFiles) |
|
2494 { |
|
2495 nsCOMPtr<nsIFile> file; |
|
2496 aProfileDir->Clone(getter_AddRefs(file)); |
|
2497 if (!file) |
|
2498 return false; |
|
2499 |
|
2500 if (aRemoveEMFiles) { |
|
2501 file->SetNativeLeafName(NS_LITERAL_CSTRING("extensions.ini")); |
|
2502 file->Remove(false); |
|
2503 } |
|
2504 |
|
2505 aLocalProfileDir->Clone(getter_AddRefs(file)); |
|
2506 if (!file) |
|
2507 return false; |
|
2508 |
|
2509 #if defined(XP_UNIX) || defined(XP_BEOS) |
|
2510 #define PLATFORM_FASL_SUFFIX ".mfasl" |
|
2511 #elif defined(XP_WIN) |
|
2512 #define PLATFORM_FASL_SUFFIX ".mfl" |
|
2513 #endif |
|
2514 |
|
2515 file->AppendNative(NS_LITERAL_CSTRING("XUL" PLATFORM_FASL_SUFFIX)); |
|
2516 file->Remove(false); |
|
2517 |
|
2518 file->SetNativeLeafName(NS_LITERAL_CSTRING("XPC" PLATFORM_FASL_SUFFIX)); |
|
2519 file->Remove(false); |
|
2520 |
|
2521 file->SetNativeLeafName(NS_LITERAL_CSTRING("startupCache")); |
|
2522 nsresult rv = file->Remove(true); |
|
2523 return NS_SUCCEEDED(rv) || rv == NS_ERROR_FILE_TARGET_DOES_NOT_EXIST; |
|
2524 } |
|
2525 |
|
2526 // To support application initiated restart via nsIAppStartup.quit, we |
|
2527 // need to save various environment variables, and then restore them |
|
2528 // before re-launching the application. |
|
2529 |
|
2530 static struct SavedVar { |
|
2531 const char *name; |
|
2532 char *value; |
|
2533 } gSavedVars[] = { |
|
2534 {"XUL_APP_FILE", nullptr} |
|
2535 }; |
|
2536 |
|
2537 static void SaveStateForAppInitiatedRestart() |
|
2538 { |
|
2539 for (size_t i = 0; i < ArrayLength(gSavedVars); ++i) { |
|
2540 const char *s = PR_GetEnv(gSavedVars[i].name); |
|
2541 if (s) |
|
2542 gSavedVars[i].value = PR_smprintf("%s=%s", gSavedVars[i].name, s); |
|
2543 } |
|
2544 } |
|
2545 |
|
2546 static void RestoreStateForAppInitiatedRestart() |
|
2547 { |
|
2548 for (size_t i = 0; i < ArrayLength(gSavedVars); ++i) { |
|
2549 if (gSavedVars[i].value) |
|
2550 PR_SetEnv(gSavedVars[i].value); |
|
2551 } |
|
2552 } |
|
2553 |
|
2554 #ifdef MOZ_CRASHREPORTER |
|
2555 // When we first initialize the crash reporter we don't have a profile, |
|
2556 // so we set the minidump path to $TEMP. Once we have a profile, |
|
2557 // we set it to $PROFILE/minidumps, creating the directory |
|
2558 // if needed. |
|
2559 static void MakeOrSetMinidumpPath(nsIFile* profD) |
|
2560 { |
|
2561 nsCOMPtr<nsIFile> dumpD; |
|
2562 profD->Clone(getter_AddRefs(dumpD)); |
|
2563 |
|
2564 if(dumpD) { |
|
2565 bool fileExists; |
|
2566 //XXX: do some more error checking here |
|
2567 dumpD->Append(NS_LITERAL_STRING("minidumps")); |
|
2568 dumpD->Exists(&fileExists); |
|
2569 if(!fileExists) { |
|
2570 dumpD->Create(nsIFile::DIRECTORY_TYPE, 0700); |
|
2571 } |
|
2572 |
|
2573 nsAutoString pathStr; |
|
2574 if(NS_SUCCEEDED(dumpD->GetPath(pathStr))) |
|
2575 CrashReporter::SetMinidumpPath(pathStr); |
|
2576 } |
|
2577 } |
|
2578 #endif |
|
2579 |
|
2580 const nsXREAppData* gAppData = nullptr; |
|
2581 |
|
2582 #ifdef MOZ_WIDGET_GTK |
|
2583 #include "prlink.h" |
|
2584 typedef void (*_g_set_application_name_fn)(const gchar *application_name); |
|
2585 typedef void (*_gtk_window_set_auto_startup_notification_fn)(gboolean setting); |
|
2586 |
|
2587 static PRFuncPtr FindFunction(const char* aName) |
|
2588 { |
|
2589 PRLibrary *lib = nullptr; |
|
2590 PRFuncPtr result = PR_FindFunctionSymbolAndLibrary(aName, &lib); |
|
2591 // Since the library was already loaded, we can safely unload it here. |
|
2592 if (lib) { |
|
2593 PR_UnloadLibrary(lib); |
|
2594 } |
|
2595 return result; |
|
2596 } |
|
2597 |
|
2598 static void MOZ_gdk_display_close(GdkDisplay *display) |
|
2599 { |
|
2600 #if CLEANUP_MEMORY |
|
2601 // XXX wallpaper for bug 417163: don't close the Display if we're using the |
|
2602 // Qt theme because we crash (in Qt code) when using jemalloc. |
|
2603 bool theme_is_qt = false; |
|
2604 GtkSettings* settings = |
|
2605 gtk_settings_get_for_screen(gdk_display_get_default_screen(display)); |
|
2606 gchar *theme_name; |
|
2607 g_object_get(settings, "gtk-theme-name", &theme_name, nullptr); |
|
2608 if (theme_name) { |
|
2609 theme_is_qt = strcmp(theme_name, "Qt") == 0; |
|
2610 if (theme_is_qt) |
|
2611 NS_WARNING("wallpaper bug 417163 for Qt theme"); |
|
2612 g_free(theme_name); |
|
2613 } |
|
2614 |
|
2615 // Get a (new) Pango context that holds a reference to the fontmap that |
|
2616 // GTK has been using. gdk_pango_context_get() must be called while GTK |
|
2617 // has a default display. |
|
2618 PangoContext *pangoContext = gdk_pango_context_get(); |
|
2619 |
|
2620 bool buggyCairoShutdown = cairo_version() < CAIRO_VERSION_ENCODE(1, 4, 0); |
|
2621 |
|
2622 if (!buggyCairoShutdown) { |
|
2623 // We should shut down GDK before we shut down libraries it depends on |
|
2624 // like Pango and cairo. But if cairo shutdown is buggy, we should |
|
2625 // shut down cairo first otherwise it may crash because of dangling |
|
2626 // references to Display objects (see bug 469831). |
|
2627 if (!theme_is_qt) |
|
2628 gdk_display_close(display); |
|
2629 } |
|
2630 |
|
2631 // Clean up PangoCairo's default fontmap. |
|
2632 // This pango_fc_font_map_shutdown call (and the associated code to |
|
2633 // get the font map) really shouldn't be needed anymore, except that |
|
2634 // it's needed to avoid having cairo_debug_reset_static_data fatally |
|
2635 // assert if we've leaked other things that hold on to the fontmap, |
|
2636 // which is something that currently happens in mochitest-plugins. |
|
2637 // Even if it didn't happen in mochitest-plugins, we probably want to |
|
2638 // avoid the crash-on-leak problem since it makes it harder to use |
|
2639 // many of our leak tools to debug leaks. |
|
2640 |
|
2641 // This doesn't take a reference. |
|
2642 PangoFontMap *fontmap = pango_context_get_font_map(pangoContext); |
|
2643 // Do some shutdown of the fontmap, which releases the fonts, clearing a |
|
2644 // bunch of circular references from the fontmap through the fonts back to |
|
2645 // itself. The shutdown that this does is much less than what's done by |
|
2646 // the fontmap's finalize, though. |
|
2647 if (PANGO_IS_FC_FONT_MAP(fontmap)) |
|
2648 pango_fc_font_map_shutdown(PANGO_FC_FONT_MAP(fontmap)); |
|
2649 g_object_unref(pangoContext); |
|
2650 |
|
2651 // Tell PangoCairo to release its default fontmap. |
|
2652 pango_cairo_font_map_set_default(nullptr); |
|
2653 |
|
2654 // cairo_debug_reset_static_data() is prototyped through cairo.h included |
|
2655 // by gtk.h. |
|
2656 #ifdef cairo_debug_reset_static_data |
|
2657 #error "Looks like we're including Mozilla's cairo instead of system cairo" |
|
2658 #endif |
|
2659 cairo_debug_reset_static_data(); |
|
2660 // FIXME: Do we need to call this in non-GTK2 cases as well? |
|
2661 FcFini(); |
|
2662 |
|
2663 if (buggyCairoShutdown) { |
|
2664 if (!theme_is_qt) |
|
2665 gdk_display_close(display); |
|
2666 } |
|
2667 #else // not CLEANUP_MEMORY |
|
2668 // Don't do anything to avoid running into driver bugs under XCloseDisplay(). |
|
2669 // See bug 973192. |
|
2670 (void) display; |
|
2671 #endif |
|
2672 } |
|
2673 #endif // MOZ_WIDGET_GTK2 |
|
2674 |
|
2675 /** |
|
2676 * NSPR will search for the "nspr_use_zone_allocator" symbol throughout |
|
2677 * the process and use it to determine whether the application defines its own |
|
2678 * memory allocator or not. |
|
2679 * |
|
2680 * Since most applications (e.g. Firefox and Thunderbird) don't use any special |
|
2681 * allocators and therefore don't define this symbol, NSPR must search the |
|
2682 * entire process, which reduces startup performance. |
|
2683 * |
|
2684 * By defining the symbol here, we can avoid the wasted lookup and hopefully |
|
2685 * improve startup performance. |
|
2686 */ |
|
2687 NS_VISIBILITY_DEFAULT PRBool nspr_use_zone_allocator = PR_FALSE; |
|
2688 |
|
2689 #ifdef CAIRO_HAS_DWRITE_FONT |
|
2690 |
|
2691 #include <dwrite.h> |
|
2692 |
|
2693 #ifdef DEBUG_DWRITE_STARTUP |
|
2694 |
|
2695 #define LOGREGISTRY(msg) LogRegistryEvent(msg) |
|
2696 |
|
2697 // for use when monitoring process |
|
2698 static void LogRegistryEvent(const wchar_t *msg) |
|
2699 { |
|
2700 HKEY dummyKey; |
|
2701 HRESULT hr; |
|
2702 wchar_t buf[512]; |
|
2703 |
|
2704 wsprintf(buf, L" log %s", msg); |
|
2705 hr = RegOpenKeyEx(HKEY_LOCAL_MACHINE, buf, 0, KEY_READ, &dummyKey); |
|
2706 if (SUCCEEDED(hr)) { |
|
2707 RegCloseKey(dummyKey); |
|
2708 } |
|
2709 } |
|
2710 #else |
|
2711 |
|
2712 #define LOGREGISTRY(msg) |
|
2713 |
|
2714 #endif |
|
2715 |
|
2716 static DWORD InitDwriteBG(LPVOID lpdwThreadParam) |
|
2717 { |
|
2718 SetThreadPriority(GetCurrentThread(), THREAD_MODE_BACKGROUND_BEGIN); |
|
2719 LOGREGISTRY(L"loading dwrite.dll"); |
|
2720 HMODULE dwdll = LoadLibraryW(L"dwrite.dll"); |
|
2721 if (dwdll) { |
|
2722 decltype(DWriteCreateFactory)* createDWriteFactory = (decltype(DWriteCreateFactory)*) |
|
2723 GetProcAddress(dwdll, "DWriteCreateFactory"); |
|
2724 if (createDWriteFactory) { |
|
2725 LOGREGISTRY(L"creating dwrite factory"); |
|
2726 IDWriteFactory *factory; |
|
2727 HRESULT hr = createDWriteFactory( |
|
2728 DWRITE_FACTORY_TYPE_SHARED, |
|
2729 __uuidof(IDWriteFactory), |
|
2730 reinterpret_cast<IUnknown**>(&factory)); |
|
2731 if (SUCCEEDED(hr)) { |
|
2732 LOGREGISTRY(L"dwrite factory done"); |
|
2733 factory->Release(); |
|
2734 LOGREGISTRY(L"freed factory"); |
|
2735 } else { |
|
2736 LOGREGISTRY(L"failed to create factory"); |
|
2737 } |
|
2738 } |
|
2739 } |
|
2740 SetThreadPriority(GetCurrentThread(), THREAD_MODE_BACKGROUND_END); |
|
2741 return 0; |
|
2742 } |
|
2743 #endif |
|
2744 |
|
2745 #ifdef USE_GLX_TEST |
|
2746 bool fire_glxtest_process(); |
|
2747 #endif |
|
2748 |
|
2749 #if defined(XP_WIN) && defined(MOZ_METRO) |
|
2750 #ifndef AHE_TYPE |
|
2751 enum AHE_TYPE { |
|
2752 AHE_DESKTOP = 0, |
|
2753 AHE_IMMERSIVE = 1 |
|
2754 }; |
|
2755 #endif |
|
2756 |
|
2757 /* |
|
2758 * The Windows launcher uses this value to decide what front end ui |
|
2759 * to launch. We always launch the same ui unless the user |
|
2760 * specifically asks to switch. Update the value on every startup |
|
2761 * based on the environment requested. |
|
2762 */ |
|
2763 void |
|
2764 SetLastWinRunType(AHE_TYPE aType) |
|
2765 { |
|
2766 HKEY key; |
|
2767 LONG result = RegOpenKeyExW(HKEY_CURRENT_USER, |
|
2768 L"SOFTWARE\\Mozilla\\Firefox", |
|
2769 0, KEY_WRITE, &key); |
|
2770 if (result != ERROR_SUCCESS) { |
|
2771 return; |
|
2772 } |
|
2773 DWORD value = (DWORD)aType; |
|
2774 result = RegSetValueEx(key, L"MetroLastAHE", 0, REG_DWORD, |
|
2775 reinterpret_cast<LPBYTE>(&value), |
|
2776 sizeof(DWORD)); |
|
2777 RegCloseKey(key); |
|
2778 } |
|
2779 #endif // defined(XP_WIN) && defined(MOZ_METRO) |
|
2780 |
|
2781 #include "GeckoProfiler.h" |
|
2782 |
|
2783 // Encapsulates startup and shutdown state for XRE_main |
|
2784 class XREMain |
|
2785 { |
|
2786 public: |
|
2787 XREMain() : |
|
2788 mScopedXPCom(nullptr) |
|
2789 , mAppData(nullptr) |
|
2790 , mStartOffline(false) |
|
2791 , mShuttingDown(false) |
|
2792 #ifdef MOZ_ENABLE_XREMOTE |
|
2793 , mDisableRemote(false) |
|
2794 #endif |
|
2795 #if defined(MOZ_WIDGET_GTK) |
|
2796 , mGdkDisplay(nullptr) |
|
2797 #endif |
|
2798 {}; |
|
2799 |
|
2800 ~XREMain() { |
|
2801 if (mAppData) { |
|
2802 delete mAppData; |
|
2803 } |
|
2804 if (mScopedXPCom) { |
|
2805 NS_WARNING("Scoped xpcom should have been deleted!"); |
|
2806 delete mScopedXPCom; |
|
2807 } |
|
2808 } |
|
2809 |
|
2810 int XRE_main(int argc, char* argv[], const nsXREAppData* aAppData); |
|
2811 int XRE_mainInit(bool* aExitFlag); |
|
2812 int XRE_mainStartup(bool* aExitFlag); |
|
2813 nsresult XRE_mainRun(); |
|
2814 |
|
2815 nsCOMPtr<nsINativeAppSupport> mNativeApp; |
|
2816 nsCOMPtr<nsIToolkitProfileService> mProfileSvc; |
|
2817 nsCOMPtr<nsIFile> mProfD; |
|
2818 nsCOMPtr<nsIFile> mProfLD; |
|
2819 nsCOMPtr<nsIProfileLock> mProfileLock; |
|
2820 #ifdef MOZ_ENABLE_XREMOTE |
|
2821 nsCOMPtr<nsIRemoteService> mRemoteService; |
|
2822 #endif |
|
2823 |
|
2824 ScopedXPCOMStartup* mScopedXPCom; |
|
2825 ScopedAppData* mAppData; |
|
2826 nsXREDirProvider mDirProvider; |
|
2827 nsAutoCString mProfileName; |
|
2828 nsAutoCString mDesktopStartupID; |
|
2829 |
|
2830 bool mStartOffline; |
|
2831 bool mShuttingDown; |
|
2832 #ifdef MOZ_ENABLE_XREMOTE |
|
2833 bool mDisableRemote; |
|
2834 #endif |
|
2835 |
|
2836 #if defined(MOZ_WIDGET_GTK) |
|
2837 GdkDisplay* mGdkDisplay; |
|
2838 #endif |
|
2839 }; |
|
2840 |
|
2841 /* |
|
2842 * XRE_mainInit - Initial setup and command line parameter processing. |
|
2843 * Main() will exit early if either return value != 0 or if aExitFlag is |
|
2844 * true. |
|
2845 */ |
|
2846 int |
|
2847 XREMain::XRE_mainInit(bool* aExitFlag) |
|
2848 { |
|
2849 if (!aExitFlag) |
|
2850 return 1; |
|
2851 *aExitFlag = false; |
|
2852 |
|
2853 StartupTimeline::Record(StartupTimeline::MAIN); |
|
2854 |
|
2855 nsresult rv; |
|
2856 ArgResult ar; |
|
2857 |
|
2858 #ifdef DEBUG |
|
2859 if (PR_GetEnv("XRE_MAIN_BREAK")) |
|
2860 NS_BREAK(); |
|
2861 #endif |
|
2862 |
|
2863 #ifdef USE_GLX_TEST |
|
2864 // bug 639842 - it's very important to fire this process BEFORE we set up |
|
2865 // error handling. indeed, this process is expected to be crashy, and we |
|
2866 // don't want the user to see its crashes. That's the whole reason for |
|
2867 // doing this in a separate process. |
|
2868 // |
|
2869 // This call will cause a fork and the fork will terminate itself separately |
|
2870 // from the usual shutdown sequence |
|
2871 fire_glxtest_process(); |
|
2872 #endif |
|
2873 |
|
2874 #if defined(XP_WIN) && defined(MOZ_METRO) |
|
2875 // Don't remove this arg, we want to pass it on to nsUpdateDriver |
|
2876 if (CheckArg("metro-update", false, nullptr, false) == ARG_FOUND || |
|
2877 XRE_GetWindowsEnvironment() == WindowsEnvironmentType_Metro) { |
|
2878 // If we're doing a restart update that was initiated from metro land, |
|
2879 // we'll be running desktop to handle the actual update. Request that |
|
2880 // after the restart we launch into metro. |
|
2881 SetLastWinRunType(AHE_IMMERSIVE); |
|
2882 } else { |
|
2883 SetLastWinRunType(AHE_DESKTOP); |
|
2884 } |
|
2885 #endif |
|
2886 |
|
2887 SetupErrorHandling(gArgv[0]); |
|
2888 |
|
2889 #ifdef CAIRO_HAS_DWRITE_FONT |
|
2890 { |
|
2891 // Bug 602792 - when DWriteCreateFactory is called the dwrite client dll |
|
2892 // starts the FntCache service if it isn't already running (it's set |
|
2893 // to manual startup by default in Windows 7 RTM). Subsequent DirectWrite |
|
2894 // calls cause the IDWriteFactory object to communicate with the FntCache |
|
2895 // service with a timeout; if there's no response after the timeout, the |
|
2896 // DirectWrite client library will assume the service isn't around and do |
|
2897 // manual font file I/O on _all_ system fonts. To avoid this, load the |
|
2898 // dwrite library and create a factory as early as possible so that the |
|
2899 // FntCache service is ready by the time it's needed. |
|
2900 |
|
2901 if (IsVistaOrLater()) { |
|
2902 CreateThread(nullptr, 0, (LPTHREAD_START_ROUTINE)&InitDwriteBG, |
|
2903 nullptr, 0, nullptr); |
|
2904 } |
|
2905 } |
|
2906 #endif |
|
2907 |
|
2908 #ifdef XP_UNIX |
|
2909 const char *home = PR_GetEnv("HOME"); |
|
2910 if (!home || !*home) { |
|
2911 struct passwd *pw = getpwuid(geteuid()); |
|
2912 if (!pw || !pw->pw_dir) { |
|
2913 Output(true, "Could not determine HOME directory"); |
|
2914 return 1; |
|
2915 } |
|
2916 SaveWordToEnv("HOME", nsDependentCString(pw->pw_dir)); |
|
2917 } |
|
2918 #endif |
|
2919 |
|
2920 #ifdef MOZ_ACCESSIBILITY_ATK |
|
2921 // Suppress atk-bridge init at startup, until mozilla accessibility is |
|
2922 // initialized. This works after gnome 2.24.2. |
|
2923 SaveToEnv("NO_AT_BRIDGE=1"); |
|
2924 #endif |
|
2925 |
|
2926 // Check for application.ini overrides |
|
2927 const char* override = nullptr; |
|
2928 ar = CheckArg("override", true, &override); |
|
2929 if (ar == ARG_BAD) { |
|
2930 Output(true, "Incorrect number of arguments passed to -override"); |
|
2931 return 1; |
|
2932 } |
|
2933 else if (ar == ARG_FOUND) { |
|
2934 nsCOMPtr<nsIFile> overrideLF; |
|
2935 rv = XRE_GetFileFromPath(override, getter_AddRefs(overrideLF)); |
|
2936 if (NS_FAILED(rv)) { |
|
2937 Output(true, "Error: unrecognized override.ini path.\n"); |
|
2938 return 1; |
|
2939 } |
|
2940 |
|
2941 rv = XRE_ParseAppData(overrideLF, mAppData); |
|
2942 if (NS_FAILED(rv)) { |
|
2943 Output(true, "Couldn't read override.ini"); |
|
2944 return 1; |
|
2945 } |
|
2946 } |
|
2947 |
|
2948 // Check sanity and correctness of app data. |
|
2949 |
|
2950 if (!mAppData->name) { |
|
2951 Output(true, "Error: App:Name not specified in application.ini\n"); |
|
2952 return 1; |
|
2953 } |
|
2954 if (!mAppData->buildID) { |
|
2955 Output(true, "Error: App:BuildID not specified in application.ini\n"); |
|
2956 return 1; |
|
2957 } |
|
2958 |
|
2959 // XXX Originally ScopedLogging was here? Now it's in XRE_main above |
|
2960 // XRE_mainInit. |
|
2961 |
|
2962 if (!mAppData->xreDirectory) { |
|
2963 nsCOMPtr<nsIFile> lf; |
|
2964 rv = XRE_GetBinaryPath(gArgv[0], getter_AddRefs(lf)); |
|
2965 if (NS_FAILED(rv)) |
|
2966 return 2; |
|
2967 |
|
2968 nsCOMPtr<nsIFile> greDir; |
|
2969 rv = lf->GetParent(getter_AddRefs(greDir)); |
|
2970 if (NS_FAILED(rv)) |
|
2971 return 2; |
|
2972 |
|
2973 greDir.forget(&mAppData->xreDirectory); |
|
2974 } |
|
2975 |
|
2976 if (!mAppData->directory) { |
|
2977 NS_IF_ADDREF(mAppData->directory = mAppData->xreDirectory); |
|
2978 } |
|
2979 |
|
2980 if (mAppData->size > offsetof(nsXREAppData, minVersion)) { |
|
2981 if (!mAppData->minVersion) { |
|
2982 Output(true, "Error: Gecko:MinVersion not specified in application.ini\n"); |
|
2983 return 1; |
|
2984 } |
|
2985 |
|
2986 if (!mAppData->maxVersion) { |
|
2987 // If no maxVersion is specified, we assume the app is only compatible |
|
2988 // with the initial preview release. Do not increment this number ever! |
|
2989 SetAllocatedString(mAppData->maxVersion, "1.*"); |
|
2990 } |
|
2991 |
|
2992 if (mozilla::Version(mAppData->minVersion) > gToolkitVersion || |
|
2993 mozilla::Version(mAppData->maxVersion) < gToolkitVersion) { |
|
2994 Output(true, "Error: Platform version '%s' is not compatible with\n" |
|
2995 "minVersion >= %s\nmaxVersion <= %s\n", |
|
2996 gToolkitVersion, |
|
2997 mAppData->minVersion, mAppData->maxVersion); |
|
2998 return 1; |
|
2999 } |
|
3000 } |
|
3001 |
|
3002 rv = mDirProvider.Initialize(mAppData->directory, mAppData->xreDirectory); |
|
3003 if (NS_FAILED(rv)) |
|
3004 return 1; |
|
3005 |
|
3006 #ifdef MOZ_CRASHREPORTER |
|
3007 if (EnvHasValue("MOZ_CRASHREPORTER")) { |
|
3008 mAppData->flags |= NS_XRE_ENABLE_CRASH_REPORTER; |
|
3009 } |
|
3010 |
|
3011 if ((mAppData->flags & NS_XRE_ENABLE_CRASH_REPORTER) && |
|
3012 NS_SUCCEEDED( |
|
3013 CrashReporter::SetExceptionHandler(mAppData->xreDirectory))) { |
|
3014 CrashReporter::UpdateCrashEventsDir(); |
|
3015 if (mAppData->crashReporterURL) |
|
3016 CrashReporter::SetServerURL(nsDependentCString(mAppData->crashReporterURL)); |
|
3017 |
|
3018 // pass some basic info from the app data |
|
3019 if (mAppData->vendor) |
|
3020 CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("Vendor"), |
|
3021 nsDependentCString(mAppData->vendor)); |
|
3022 if (mAppData->name) |
|
3023 CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("ProductName"), |
|
3024 nsDependentCString(mAppData->name)); |
|
3025 if (mAppData->ID) |
|
3026 CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("ProductID"), |
|
3027 nsDependentCString(mAppData->ID)); |
|
3028 if (mAppData->version) |
|
3029 CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("Version"), |
|
3030 nsDependentCString(mAppData->version)); |
|
3031 if (mAppData->buildID) |
|
3032 CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("BuildID"), |
|
3033 nsDependentCString(mAppData->buildID)); |
|
3034 |
|
3035 nsDependentCString releaseChannel(NS_STRINGIFY(MOZ_UPDATE_CHANNEL)); |
|
3036 CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("ReleaseChannel"), |
|
3037 releaseChannel); |
|
3038 #ifdef MOZ_LINKER |
|
3039 CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("CrashAddressLikelyWrong"), |
|
3040 IsSignalHandlingBroken() ? NS_LITERAL_CSTRING("1") |
|
3041 : NS_LITERAL_CSTRING("0")); |
|
3042 #endif |
|
3043 CrashReporter::SetRestartArgs(gArgc, gArgv); |
|
3044 |
|
3045 // annotate other data (user id etc) |
|
3046 nsCOMPtr<nsIFile> userAppDataDir; |
|
3047 if (NS_SUCCEEDED(mDirProvider.GetUserAppDataDirectory( |
|
3048 getter_AddRefs(userAppDataDir)))) { |
|
3049 CrashReporter::SetupExtraData(userAppDataDir, |
|
3050 nsDependentCString(mAppData->buildID)); |
|
3051 |
|
3052 // see if we have a crashreporter-override.ini in the application directory |
|
3053 nsCOMPtr<nsIFile> overrideini; |
|
3054 bool exists; |
|
3055 if (NS_SUCCEEDED(mDirProvider.GetAppDir()->Clone(getter_AddRefs(overrideini))) && |
|
3056 NS_SUCCEEDED(overrideini->AppendNative(NS_LITERAL_CSTRING("crashreporter-override.ini"))) && |
|
3057 NS_SUCCEEDED(overrideini->Exists(&exists)) && |
|
3058 exists) { |
|
3059 #ifdef XP_WIN |
|
3060 nsAutoString overridePathW; |
|
3061 overrideini->GetPath(overridePathW); |
|
3062 NS_ConvertUTF16toUTF8 overridePath(overridePathW); |
|
3063 #else |
|
3064 nsAutoCString overridePath; |
|
3065 overrideini->GetNativePath(overridePath); |
|
3066 #endif |
|
3067 |
|
3068 SaveWordToEnv("MOZ_CRASHREPORTER_STRINGS_OVERRIDE", overridePath); |
|
3069 } |
|
3070 } |
|
3071 } |
|
3072 #endif |
|
3073 |
|
3074 #ifdef XP_MACOSX |
|
3075 if (EnvHasValue("MOZ_LAUNCHED_CHILD")) { |
|
3076 // This is needed, on relaunch, to force the OS to use the "Cocoa Dock |
|
3077 // API". Otherwise the call to ReceiveNextEvent() below will make it |
|
3078 // use the "Carbon Dock API". For more info see bmo bug 377166. |
|
3079 EnsureUseCocoaDockAPI(); |
|
3080 |
|
3081 // When the app relaunches, the original process exits. This causes |
|
3082 // the dock tile to stop bouncing, lose the "running" triangle, and |
|
3083 // if the tile does not permanently reside in the Dock, even disappear. |
|
3084 // This can be confusing to the user, who is expecting the app to launch. |
|
3085 // Calling ReceiveNextEvent without requesting any event is enough to |
|
3086 // cause a dock tile for the child process to appear. |
|
3087 const EventTypeSpec kFakeEventList[] = { { INT_MAX, INT_MAX } }; |
|
3088 EventRef event; |
|
3089 ::ReceiveNextEvent(GetEventTypeCount(kFakeEventList), kFakeEventList, |
|
3090 kEventDurationNoWait, false, &event); |
|
3091 } |
|
3092 |
|
3093 if (CheckArg("foreground")) { |
|
3094 // The original process communicates that it was in the foreground by |
|
3095 // adding this argument. This new process, which is taking over for |
|
3096 // the old one, should make itself the active application. |
|
3097 ProcessSerialNumber psn; |
|
3098 if (::GetCurrentProcess(&psn) == noErr) |
|
3099 ::SetFrontProcess(&psn); |
|
3100 } |
|
3101 #endif |
|
3102 |
|
3103 SaveToEnv("MOZ_LAUNCHED_CHILD="); |
|
3104 |
|
3105 gRestartArgc = gArgc; |
|
3106 gRestartArgv = (char**) malloc(sizeof(char*) * (gArgc + 1 + (override ? 2 : 0))); |
|
3107 if (!gRestartArgv) { |
|
3108 return 1; |
|
3109 } |
|
3110 |
|
3111 int i; |
|
3112 for (i = 0; i < gArgc; ++i) { |
|
3113 gRestartArgv[i] = gArgv[i]; |
|
3114 } |
|
3115 |
|
3116 // Add the -override argument back (it is removed automatically be CheckArg) if there is one |
|
3117 if (override) { |
|
3118 gRestartArgv[gRestartArgc++] = const_cast<char*>("-override"); |
|
3119 gRestartArgv[gRestartArgc++] = const_cast<char*>(override); |
|
3120 } |
|
3121 |
|
3122 gRestartArgv[gRestartArgc] = nullptr; |
|
3123 |
|
3124 |
|
3125 if (EnvHasValue("MOZ_SAFE_MODE_RESTART")) { |
|
3126 gSafeMode = true; |
|
3127 // unset the env variable |
|
3128 SaveToEnv("MOZ_SAFE_MODE_RESTART="); |
|
3129 } |
|
3130 |
|
3131 ar = CheckArg("safe-mode", true); |
|
3132 if (ar == ARG_BAD) { |
|
3133 PR_fprintf(PR_STDERR, "Error: argument -safe-mode is invalid when argument -osint is specified\n"); |
|
3134 return 1; |
|
3135 } else if (ar == ARG_FOUND) { |
|
3136 gSafeMode = true; |
|
3137 } |
|
3138 |
|
3139 #ifdef XP_WIN |
|
3140 // If the shift key is pressed and the ctrl and / or alt keys are not pressed |
|
3141 // during startup start in safe mode. GetKeyState returns a short and the high |
|
3142 // order bit will be 1 if the key is pressed. By masking the returned short |
|
3143 // with 0x8000 the result will be 0 if the key is not pressed and non-zero |
|
3144 // otherwise. |
|
3145 if (GetKeyState(VK_SHIFT) & 0x8000 && |
|
3146 !(GetKeyState(VK_CONTROL) & 0x8000) && !(GetKeyState(VK_MENU) & 0x8000)) { |
|
3147 gSafeMode = true; |
|
3148 } |
|
3149 #endif |
|
3150 |
|
3151 #ifdef XP_MACOSX |
|
3152 if (GetCurrentEventKeyModifiers() & optionKey) |
|
3153 gSafeMode = true; |
|
3154 #endif |
|
3155 |
|
3156 // In the Tor Browser, remoting is disabled by default unless -osint is used. |
|
3157 bool allowRemote = (CheckArg("allow-remote") == ARG_FOUND); |
|
3158 if (!allowRemote && (CheckArg("osint", false, nullptr, false) != ARG_FOUND)) |
|
3159 SaveToEnv("MOZ_NO_REMOTE=1"); |
|
3160 |
|
3161 // Handle -no-remote and -new-instance command line arguments. Setup |
|
3162 // the environment to better accommodate other components and various |
|
3163 // restart scenarios. |
|
3164 ar = CheckArg("no-remote", true); |
|
3165 if (ar == ARG_BAD) { |
|
3166 PR_fprintf(PR_STDERR, "Error: argument -no-remote is invalid when argument -osint is specified\n"); |
|
3167 return 1; |
|
3168 } else if ((ar == ARG_FOUND) && allowRemote) { |
|
3169 PR_fprintf(PR_STDERR, "Error: argument -no-remote is invalid when argument -allow-remote is specified\n"); |
|
3170 return 1; |
|
3171 } |
|
3172 |
|
3173 ar = CheckArg("new-instance", true); |
|
3174 if (ar == ARG_BAD) { |
|
3175 PR_fprintf(PR_STDERR, "Error: argument -new-instance is invalid when argument -osint is specified\n"); |
|
3176 return 1; |
|
3177 } else if (ar == ARG_FOUND) { |
|
3178 SaveToEnv("MOZ_NEW_INSTANCE=1"); |
|
3179 } |
|
3180 |
|
3181 // Handle -help and -version command line arguments. |
|
3182 // They should return quickly, so we deal with them here. |
|
3183 if (CheckArg("h") || CheckArg("help") || CheckArg("?")) { |
|
3184 DumpHelp(); |
|
3185 *aExitFlag = true; |
|
3186 return 0; |
|
3187 } |
|
3188 |
|
3189 if (CheckArg("v") || CheckArg("version")) { |
|
3190 DumpVersion(); |
|
3191 *aExitFlag = true; |
|
3192 return 0; |
|
3193 } |
|
3194 |
|
3195 #ifdef NS_TRACE_MALLOC |
|
3196 gArgc = NS_TraceMallocStartupArgs(gArgc, gArgv); |
|
3197 #endif |
|
3198 |
|
3199 rv = XRE_InitCommandLine(gArgc, gArgv); |
|
3200 NS_ENSURE_SUCCESS(rv, 1); |
|
3201 |
|
3202 // Check for -register, which registers chrome and then exits immediately. |
|
3203 ar = CheckArg("register", true); |
|
3204 if (ar == ARG_BAD) { |
|
3205 PR_fprintf(PR_STDERR, "Error: argument -register is invalid when argument -osint is specified\n"); |
|
3206 return 1; |
|
3207 } else if (ar == ARG_FOUND) { |
|
3208 ScopedXPCOMStartup xpcom; |
|
3209 rv = xpcom.Initialize(); |
|
3210 NS_ENSURE_SUCCESS(rv, 1); |
|
3211 { |
|
3212 nsCOMPtr<nsIChromeRegistry> chromeReg = |
|
3213 mozilla::services::GetChromeRegistryService(); |
|
3214 NS_ENSURE_TRUE(chromeReg, 1); |
|
3215 |
|
3216 chromeReg->CheckForNewChrome(); |
|
3217 } |
|
3218 *aExitFlag = true; |
|
3219 return 0; |
|
3220 } |
|
3221 |
|
3222 if (PR_GetEnv("MOZ_RUN_GTEST")) { |
|
3223 int result; |
|
3224 // RunGTest will only be set if we're in xul-unit |
|
3225 if (mozilla::RunGTest) { |
|
3226 result = mozilla::RunGTest(); |
|
3227 } else { |
|
3228 result = 1; |
|
3229 printf("TEST-UNEXPECTED-FAIL | gtest | Not compiled with enable-tests\n"); |
|
3230 } |
|
3231 *aExitFlag = true; |
|
3232 return result; |
|
3233 } |
|
3234 |
|
3235 return 0; |
|
3236 } |
|
3237 |
|
3238 #ifdef MOZ_CRASHREPORTER |
|
3239 #ifdef XP_WIN |
|
3240 /** |
|
3241 * Uses WMI to read some manufacturer information that may be useful for |
|
3242 * diagnosing hardware-specific crashes. This function is best-effort; failures |
|
3243 * shouldn't burden the caller. COM must be initialized before calling. |
|
3244 */ |
|
3245 static void AnnotateSystemManufacturer() |
|
3246 { |
|
3247 nsRefPtr<IWbemLocator> locator; |
|
3248 |
|
3249 HRESULT hr = CoCreateInstance(CLSID_WbemLocator, nullptr, CLSCTX_INPROC_SERVER, |
|
3250 IID_IWbemLocator, getter_AddRefs(locator)); |
|
3251 |
|
3252 if (FAILED(hr)) { |
|
3253 return; |
|
3254 } |
|
3255 |
|
3256 nsRefPtr<IWbemServices> services; |
|
3257 |
|
3258 hr = locator->ConnectServer(_bstr_t(L"ROOT\\CIMV2"), nullptr, nullptr, nullptr, |
|
3259 0, nullptr, nullptr, getter_AddRefs(services)); |
|
3260 |
|
3261 if (FAILED(hr)) { |
|
3262 return; |
|
3263 } |
|
3264 |
|
3265 hr = CoSetProxyBlanket(services, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, nullptr, |
|
3266 RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, |
|
3267 nullptr, EOAC_NONE); |
|
3268 |
|
3269 if (FAILED(hr)) { |
|
3270 return; |
|
3271 } |
|
3272 |
|
3273 nsRefPtr<IEnumWbemClassObject> enumerator; |
|
3274 |
|
3275 hr = services->ExecQuery(_bstr_t(L"WQL"), _bstr_t(L"SELECT * FROM Win32_BIOS"), |
|
3276 WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, |
|
3277 nullptr, getter_AddRefs(enumerator)); |
|
3278 |
|
3279 if (FAILED(hr) || !enumerator) { |
|
3280 return; |
|
3281 } |
|
3282 |
|
3283 nsRefPtr<IWbemClassObject> classObject; |
|
3284 ULONG results; |
|
3285 |
|
3286 hr = enumerator->Next(WBEM_INFINITE, 1, getter_AddRefs(classObject), &results); |
|
3287 |
|
3288 if (FAILED(hr) || results == 0) { |
|
3289 return; |
|
3290 } |
|
3291 |
|
3292 VARIANT value; |
|
3293 VariantInit(&value); |
|
3294 |
|
3295 hr = classObject->Get(L"Manufacturer", 0, &value, 0, 0); |
|
3296 |
|
3297 if (SUCCEEDED(hr) && V_VT(&value) == VT_BSTR) { |
|
3298 CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("BIOS_Manufacturer"), |
|
3299 NS_ConvertUTF16toUTF8(V_BSTR(&value))); |
|
3300 } |
|
3301 |
|
3302 VariantClear(&value); |
|
3303 } |
|
3304 |
|
3305 static void PR_CALLBACK AnnotateSystemManufacturer_ThreadStart(void*) |
|
3306 { |
|
3307 HRESULT hr = CoInitialize(nullptr); |
|
3308 |
|
3309 if (FAILED(hr)) { |
|
3310 return; |
|
3311 } |
|
3312 |
|
3313 AnnotateSystemManufacturer(); |
|
3314 |
|
3315 CoUninitialize(); |
|
3316 } |
|
3317 #endif |
|
3318 #endif |
|
3319 |
|
3320 namespace mozilla { |
|
3321 ShutdownChecksMode gShutdownChecks = SCM_NOTHING; |
|
3322 } |
|
3323 |
|
3324 static void SetShutdownChecks() { |
|
3325 // Set default first. On debug builds we crash. On nightly and local |
|
3326 // builds we record. Nightlies will then send the info via telemetry, |
|
3327 // but it is usefull to have the data in about:telemetry in local builds |
|
3328 // too. |
|
3329 |
|
3330 #ifdef DEBUG |
|
3331 gShutdownChecks = SCM_CRASH; |
|
3332 #else |
|
3333 const char* releaseChannel = NS_STRINGIFY(MOZ_UPDATE_CHANNEL); |
|
3334 if (strcmp(releaseChannel, "nightly") == 0 || |
|
3335 strcmp(releaseChannel, "default") == 0) { |
|
3336 gShutdownChecks = SCM_RECORD; |
|
3337 } else { |
|
3338 gShutdownChecks = SCM_NOTHING; |
|
3339 } |
|
3340 #endif |
|
3341 |
|
3342 // We let an environment variable override the default so that addons |
|
3343 // authors can use it for debugging shutdown with released firefox versions. |
|
3344 const char* mozShutdownChecksEnv = PR_GetEnv("MOZ_SHUTDOWN_CHECKS"); |
|
3345 if (mozShutdownChecksEnv) { |
|
3346 if (strcmp(mozShutdownChecksEnv, "crash") == 0) { |
|
3347 gShutdownChecks = SCM_CRASH; |
|
3348 } else if (strcmp(mozShutdownChecksEnv, "record") == 0) { |
|
3349 gShutdownChecks = SCM_RECORD; |
|
3350 } else if (strcmp(mozShutdownChecksEnv, "nothing") == 0) { |
|
3351 gShutdownChecks = SCM_NOTHING; |
|
3352 } |
|
3353 } |
|
3354 |
|
3355 } |
|
3356 |
|
3357 /* |
|
3358 * XRE_mainStartup - Initializes the profile and various other services. |
|
3359 * Main() will exit early if either return value != 0 or if aExitFlag is |
|
3360 * true. |
|
3361 */ |
|
3362 int |
|
3363 XREMain::XRE_mainStartup(bool* aExitFlag) |
|
3364 { |
|
3365 nsresult rv; |
|
3366 |
|
3367 if (!aExitFlag) |
|
3368 return 1; |
|
3369 *aExitFlag = false; |
|
3370 |
|
3371 SetShutdownChecks(); |
|
3372 |
|
3373 |
|
3374 // Enable Telemetry IO Reporting on DEBUG, nightly and local builds |
|
3375 #ifdef DEBUG |
|
3376 mozilla::Telemetry::InitIOReporting(gAppData->xreDirectory); |
|
3377 #else |
|
3378 { |
|
3379 const char* releaseChannel = NS_STRINGIFY(MOZ_UPDATE_CHANNEL); |
|
3380 if (strcmp(releaseChannel, "nightly") == 0 || |
|
3381 strcmp(releaseChannel, "default") == 0) { |
|
3382 mozilla::Telemetry::InitIOReporting(gAppData->xreDirectory); |
|
3383 } |
|
3384 } |
|
3385 #endif /* DEBUG */ |
|
3386 |
|
3387 #if defined(MOZ_WIDGET_GTK) || defined(MOZ_ENABLE_XREMOTE) |
|
3388 // Stash DESKTOP_STARTUP_ID in malloc'ed memory because gtk_init will clear it. |
|
3389 #define HAVE_DESKTOP_STARTUP_ID |
|
3390 const char* desktopStartupIDEnv = PR_GetEnv("DESKTOP_STARTUP_ID"); |
|
3391 if (desktopStartupIDEnv) { |
|
3392 mDesktopStartupID.Assign(desktopStartupIDEnv); |
|
3393 } |
|
3394 #endif |
|
3395 |
|
3396 #if defined(MOZ_WIDGET_QT) |
|
3397 nsQAppInstance::AddRef(gArgc, gArgv, true); |
|
3398 |
|
3399 QStringList nonQtArguments = qApp->arguments(); |
|
3400 gQtOnlyArgc = 1; |
|
3401 gQtOnlyArgv = (char**) malloc(sizeof(char*) |
|
3402 * (gRestartArgc - nonQtArguments.size() + 2)); |
|
3403 |
|
3404 // copy binary path |
|
3405 gQtOnlyArgv[0] = gRestartArgv[0]; |
|
3406 |
|
3407 for (int i = 1; i < gRestartArgc; ++i) { |
|
3408 if (!nonQtArguments.contains(gRestartArgv[i])) { |
|
3409 // copy arguments used by Qt for later |
|
3410 gQtOnlyArgv[gQtOnlyArgc++] = gRestartArgv[i]; |
|
3411 } |
|
3412 } |
|
3413 gQtOnlyArgv[gQtOnlyArgc] = nullptr; |
|
3414 #endif |
|
3415 #if defined(MOZ_WIDGET_GTK) |
|
3416 // setup for private colormap. Ideally we'd like to do this |
|
3417 // in nsAppShell::Create, but we need to get in before gtk |
|
3418 // has been initialized to make sure everything is running |
|
3419 // consistently. |
|
3420 #if (MOZ_WIDGET_GTK == 2) |
|
3421 if (CheckArg("install")) |
|
3422 gdk_rgb_set_install(TRUE); |
|
3423 #endif |
|
3424 |
|
3425 // Set program name to the one defined in application.ini. |
|
3426 { |
|
3427 nsAutoCString program(gAppData->name); |
|
3428 ToLowerCase(program); |
|
3429 g_set_prgname(program.get()); |
|
3430 } |
|
3431 |
|
3432 // Initialize GTK here for splash. |
|
3433 |
|
3434 // Open the display ourselves instead of using gtk_init, so that we can |
|
3435 // close it without fear that one day gtk might clean up the display it |
|
3436 // opens. |
|
3437 if (!gtk_parse_args(&gArgc, &gArgv)) |
|
3438 return 1; |
|
3439 |
|
3440 // display_name is owned by gdk. |
|
3441 const char *display_name = gdk_get_display_arg_name(); |
|
3442 if (display_name) { |
|
3443 SaveWordToEnv("DISPLAY", nsDependentCString(display_name)); |
|
3444 } else { |
|
3445 display_name = PR_GetEnv("DISPLAY"); |
|
3446 if (!display_name) { |
|
3447 PR_fprintf(PR_STDERR, "Error: no display specified\n"); |
|
3448 return 1; |
|
3449 } |
|
3450 } |
|
3451 #endif /* MOZ_WIDGET_GTK2 */ |
|
3452 |
|
3453 #ifdef MOZ_ENABLE_XREMOTE |
|
3454 // handle -remote now that xpcom is fired up |
|
3455 bool newInstance; |
|
3456 { |
|
3457 char *e = PR_GetEnv("MOZ_NO_REMOTE"); |
|
3458 mDisableRemote = (e && *e); |
|
3459 if (mDisableRemote) { |
|
3460 newInstance = true; |
|
3461 } else { |
|
3462 e = PR_GetEnv("MOZ_NEW_INSTANCE"); |
|
3463 newInstance = (e && *e); |
|
3464 } |
|
3465 } |
|
3466 |
|
3467 const char* xremotearg; |
|
3468 ArgResult ar = CheckArg("remote", true, &xremotearg); |
|
3469 if (ar == ARG_BAD) { |
|
3470 PR_fprintf(PR_STDERR, "Error: -remote requires an argument\n"); |
|
3471 return 1; |
|
3472 } |
|
3473 const char* desktopStartupIDPtr = |
|
3474 mDesktopStartupID.IsEmpty() ? nullptr : mDesktopStartupID.get(); |
|
3475 if (ar) { |
|
3476 *aExitFlag = true; |
|
3477 return HandleRemoteArgument(xremotearg, desktopStartupIDPtr); |
|
3478 } |
|
3479 |
|
3480 if (!newInstance) { |
|
3481 // Try to remote the entire command line. If this fails, start up normally. |
|
3482 RemoteResult rr = RemoteCommandLine(desktopStartupIDPtr); |
|
3483 if (rr == REMOTE_FOUND) { |
|
3484 *aExitFlag = true; |
|
3485 return 0; |
|
3486 } |
|
3487 else if (rr == REMOTE_ARG_BAD) |
|
3488 return 1; |
|
3489 } |
|
3490 #endif |
|
3491 #ifdef MOZ_X11 |
|
3492 // Init X11 in thread-safe mode. Must be called prior to the first call to XOpenDisplay |
|
3493 // (called inside gdk_display_open). This is a requirement for off main tread compositing. |
|
3494 // This is done only on X11 platforms if the environment variable MOZ_USE_OMTC is set so |
|
3495 // as to avoid overhead when omtc is not used. |
|
3496 // |
|
3497 // On nightly builds, we call this by default to enable OMTC for Electrolysis testing. On |
|
3498 // aurora, beta, and release builds, there is a small tpaint regression from enabling this |
|
3499 // call, so it sits behind an environment variable. |
|
3500 // |
|
3501 // An environment variable is used instead of a pref on X11 platforms because we start having |
|
3502 // access to prefs long after the first call to XOpenDisplay which is hard to change due to |
|
3503 // interdependencies in the initialization. |
|
3504 # ifndef NIGHTLY_BUILD |
|
3505 if (PR_GetEnv("MOZ_USE_OMTC") || |
|
3506 PR_GetEnv("MOZ_OMTC_ENABLED")) |
|
3507 # endif |
|
3508 { |
|
3509 XInitThreads(); |
|
3510 } |
|
3511 #endif |
|
3512 #if defined(MOZ_WIDGET_GTK) |
|
3513 mGdkDisplay = gdk_display_open(display_name); |
|
3514 if (!mGdkDisplay) { |
|
3515 PR_fprintf(PR_STDERR, "Error: cannot open display: %s\n", display_name); |
|
3516 return 1; |
|
3517 } |
|
3518 gdk_display_manager_set_default_display (gdk_display_manager_get(), |
|
3519 mGdkDisplay); |
|
3520 |
|
3521 // g_set_application_name () is only defined in glib2.2 and higher. |
|
3522 _g_set_application_name_fn _g_set_application_name = |
|
3523 (_g_set_application_name_fn)FindFunction("g_set_application_name"); |
|
3524 if (_g_set_application_name) { |
|
3525 _g_set_application_name(mAppData->name); |
|
3526 } |
|
3527 _gtk_window_set_auto_startup_notification_fn _gtk_window_set_auto_startup_notification = |
|
3528 (_gtk_window_set_auto_startup_notification_fn)FindFunction("gtk_window_set_auto_startup_notification"); |
|
3529 if (_gtk_window_set_auto_startup_notification) { |
|
3530 _gtk_window_set_auto_startup_notification(false); |
|
3531 } |
|
3532 |
|
3533 #if (MOZ_WIDGET_GTK == 2) |
|
3534 gtk_widget_set_default_colormap(gdk_rgb_get_colormap()); |
|
3535 #endif /* (MOZ_WIDGET_GTK == 2) */ |
|
3536 #endif /* defined(MOZ_WIDGET_GTK) */ |
|
3537 #ifdef MOZ_X11 |
|
3538 // Do this after initializing GDK, or GDK will install its own handler. |
|
3539 InstallX11ErrorHandler(); |
|
3540 #endif |
|
3541 |
|
3542 // Call the code to install our handler |
|
3543 #ifdef MOZ_JPROF |
|
3544 setupProfilingStuff(); |
|
3545 #endif |
|
3546 |
|
3547 rv = NS_CreateNativeAppSupport(getter_AddRefs(mNativeApp)); |
|
3548 if (NS_FAILED(rv)) |
|
3549 return 1; |
|
3550 |
|
3551 bool canRun = false; |
|
3552 rv = mNativeApp->Start(&canRun); |
|
3553 if (NS_FAILED(rv) || !canRun) { |
|
3554 return 1; |
|
3555 } |
|
3556 |
|
3557 #if defined(HAVE_DESKTOP_STARTUP_ID) && defined(MOZ_WIDGET_GTK) |
|
3558 // DESKTOP_STARTUP_ID is cleared now, |
|
3559 // we recover it in case we need a restart. |
|
3560 if (!mDesktopStartupID.IsEmpty()) { |
|
3561 nsAutoCString desktopStartupEnv; |
|
3562 desktopStartupEnv.AssignLiteral("DESKTOP_STARTUP_ID="); |
|
3563 desktopStartupEnv.Append(mDesktopStartupID); |
|
3564 // Leak it with extreme prejudice! |
|
3565 PR_SetEnv(ToNewCString(desktopStartupEnv)); |
|
3566 } |
|
3567 #endif |
|
3568 |
|
3569 #if defined(USE_MOZ_UPDATER) |
|
3570 // Check for and process any available updates |
|
3571 nsCOMPtr<nsIFile> updRoot; |
|
3572 bool persistent; |
|
3573 rv = mDirProvider.GetFile(XRE_UPDATE_ROOT_DIR, &persistent, |
|
3574 getter_AddRefs(updRoot)); |
|
3575 // XRE_UPDATE_ROOT_DIR may fail. Fallback to appDir if failed |
|
3576 if (NS_FAILED(rv)) |
|
3577 updRoot = mDirProvider.GetAppDir(); |
|
3578 |
|
3579 // If the MOZ_PROCESS_UPDATES environment variable already exists, then |
|
3580 // we are being called from the callback application. |
|
3581 if (EnvHasValue("MOZ_PROCESS_UPDATES")) { |
|
3582 // If the caller has asked us to log our arguments, do so. This is used |
|
3583 // to make sure that the maintenance service successfully launches the |
|
3584 // callback application. |
|
3585 const char *logFile = nullptr; |
|
3586 if (ARG_FOUND == CheckArg("dump-args", false, &logFile)) { |
|
3587 FILE* logFP = fopen(logFile, "wb"); |
|
3588 if (logFP) { |
|
3589 for (int i = 1; i < gRestartArgc; ++i) { |
|
3590 fprintf(logFP, "%s\n", gRestartArgv[i]); |
|
3591 } |
|
3592 fclose(logFP); |
|
3593 } |
|
3594 } |
|
3595 *aExitFlag = true; |
|
3596 return 0; |
|
3597 } |
|
3598 |
|
3599 // Support for processing an update and exiting. The MOZ_PROCESS_UPDATES |
|
3600 // environment variable will be part of the updater's environment and the |
|
3601 // application that is relaunched by the updater. When the application is |
|
3602 // relaunched by the updater it will be removed below and the application |
|
3603 // will exit. |
|
3604 if (CheckArg("process-updates")) { |
|
3605 SaveToEnv("MOZ_PROCESS_UPDATES=1"); |
|
3606 } |
|
3607 nsCOMPtr<nsIFile> exeFile, exeDir; |
|
3608 rv = mDirProvider.GetFile(XRE_EXECUTABLE_FILE, &persistent, |
|
3609 getter_AddRefs(exeFile)); |
|
3610 NS_ENSURE_SUCCESS(rv, 1); |
|
3611 rv = exeFile->GetParent(getter_AddRefs(exeDir)); |
|
3612 NS_ENSURE_SUCCESS(rv, 1); |
|
3613 #ifdef TOR_BROWSER_UPDATE |
|
3614 nsAutoCString compatVersion(TOR_BROWSER_VERSION); |
|
3615 #endif |
|
3616 ProcessUpdates(mDirProvider.GetGREDir(), |
|
3617 exeDir, |
|
3618 updRoot, |
|
3619 gRestartArgc, |
|
3620 gRestartArgv, |
|
3621 #ifdef TOR_BROWSER_UPDATE |
|
3622 compatVersion.get() |
|
3623 #else |
|
3624 mAppData->version |
|
3625 #endif |
|
3626 ); |
|
3627 if (EnvHasValue("MOZ_PROCESS_UPDATES")) { |
|
3628 SaveToEnv("MOZ_PROCESS_UPDATES="); |
|
3629 *aExitFlag = true; |
|
3630 return 0; |
|
3631 } |
|
3632 #if defined(XP_WIN) && defined(MOZ_METRO) |
|
3633 if (CheckArg("metro-update", false) == ARG_FOUND) { |
|
3634 *aExitFlag = true; |
|
3635 return 0; |
|
3636 } |
|
3637 #endif |
|
3638 #endif |
|
3639 |
|
3640 rv = NS_NewToolkitProfileService(getter_AddRefs(mProfileSvc)); |
|
3641 if (rv == NS_ERROR_FILE_ACCESS_DENIED) { |
|
3642 PR_fprintf(PR_STDERR, "Error: Access was denied while trying to open files in " \ |
|
3643 "your profile directory.\n"); |
|
3644 } |
|
3645 if (NS_FAILED(rv)) { |
|
3646 // We failed to choose or create profile - notify user and quit |
|
3647 ProfileMissingDialog(mNativeApp); |
|
3648 return 1; |
|
3649 } |
|
3650 |
|
3651 rv = SelectProfile(getter_AddRefs(mProfileLock), mProfileSvc, mNativeApp, &mStartOffline, |
|
3652 &mProfileName); |
|
3653 if (rv == NS_ERROR_LAUNCHED_CHILD_PROCESS || |
|
3654 rv == NS_ERROR_ABORT) { |
|
3655 *aExitFlag = true; |
|
3656 return 0; |
|
3657 } |
|
3658 |
|
3659 if (NS_FAILED(rv)) { |
|
3660 // We failed to choose or create profile - notify user and quit |
|
3661 ProfileMissingDialog(mNativeApp); |
|
3662 return 1; |
|
3663 } |
|
3664 gProfileLock = mProfileLock; |
|
3665 |
|
3666 rv = mProfileLock->GetDirectory(getter_AddRefs(mProfD)); |
|
3667 NS_ENSURE_SUCCESS(rv, 1); |
|
3668 |
|
3669 rv = mProfileLock->GetLocalDirectory(getter_AddRefs(mProfLD)); |
|
3670 NS_ENSURE_SUCCESS(rv, 1); |
|
3671 |
|
3672 rv = mDirProvider.SetProfile(mProfD, mProfLD); |
|
3673 NS_ENSURE_SUCCESS(rv, 1); |
|
3674 |
|
3675 //////////////////////// NOW WE HAVE A PROFILE //////////////////////// |
|
3676 |
|
3677 mozilla::Telemetry::SetProfileDir(mProfD); |
|
3678 |
|
3679 #ifdef MOZ_CRASHREPORTER |
|
3680 if (mAppData->flags & NS_XRE_ENABLE_CRASH_REPORTER) |
|
3681 MakeOrSetMinidumpPath(mProfD); |
|
3682 |
|
3683 CrashReporter::UpdateCrashEventsDir(); |
|
3684 #endif |
|
3685 |
|
3686 nsAutoCString version; |
|
3687 BuildVersion(version); |
|
3688 |
|
3689 #ifdef TARGET_OS_ABI |
|
3690 NS_NAMED_LITERAL_CSTRING(osABI, TARGET_OS_ABI); |
|
3691 #else |
|
3692 // No TARGET_XPCOM_ABI, but at least the OS is known |
|
3693 NS_NAMED_LITERAL_CSTRING(osABI, OS_TARGET "_UNKNOWN"); |
|
3694 #endif |
|
3695 |
|
3696 // Check for version compatibility with the last version of the app this |
|
3697 // profile was started with. The format of the version stamp is defined |
|
3698 // by the BuildVersion function. |
|
3699 // Also check to see if something has happened to invalidate our |
|
3700 // fastload caches, like an extension upgrade or installation. |
|
3701 |
|
3702 // If we see .purgecaches, that means someone did a make. |
|
3703 // Re-register components to catch potential changes. |
|
3704 nsCOMPtr<nsIFile> flagFile; |
|
3705 |
|
3706 rv = NS_ERROR_FILE_NOT_FOUND; |
|
3707 nsCOMPtr<nsIFile> fFlagFile; |
|
3708 if (mAppData->directory) { |
|
3709 rv = mAppData->directory->Clone(getter_AddRefs(fFlagFile)); |
|
3710 } |
|
3711 flagFile = do_QueryInterface(fFlagFile); |
|
3712 if (flagFile) { |
|
3713 flagFile->AppendNative(FILE_INVALIDATE_CACHES); |
|
3714 } |
|
3715 |
|
3716 bool cachesOK; |
|
3717 bool versionOK = CheckCompatibility(mProfD, version, osABI, |
|
3718 mDirProvider.GetGREDir(), |
|
3719 mAppData->directory, flagFile, |
|
3720 &cachesOK); |
|
3721 if (CheckArg("purgecaches")) { |
|
3722 cachesOK = false; |
|
3723 } |
|
3724 if (PR_GetEnv("MOZ_PURGE_CACHES")) { |
|
3725 cachesOK = false; |
|
3726 } |
|
3727 |
|
3728 // Every time a profile is loaded by a build with a different version, |
|
3729 // it updates the compatibility.ini file saying what version last wrote |
|
3730 // the fastload caches. On subsequent launches if the version matches, |
|
3731 // there is no need for re-registration. If the user loads the same |
|
3732 // profile in different builds the component registry must be |
|
3733 // re-generated to prevent mysterious component loading failures. |
|
3734 // |
|
3735 bool startupCacheValid = true; |
|
3736 if (gSafeMode) { |
|
3737 startupCacheValid = RemoveComponentRegistries(mProfD, mProfLD, false); |
|
3738 WriteVersion(mProfD, NS_LITERAL_CSTRING("Safe Mode"), osABI, |
|
3739 mDirProvider.GetGREDir(), mAppData->directory, !startupCacheValid); |
|
3740 } |
|
3741 else if (versionOK) { |
|
3742 if (!cachesOK) { |
|
3743 // Remove caches, forcing component re-registration. |
|
3744 // The new list of additional components directories is derived from |
|
3745 // information in "extensions.ini". |
|
3746 startupCacheValid = RemoveComponentRegistries(mProfD, mProfLD, false); |
|
3747 |
|
3748 // Rewrite compatibility.ini to remove the flag |
|
3749 WriteVersion(mProfD, version, osABI, |
|
3750 mDirProvider.GetGREDir(), mAppData->directory, !startupCacheValid); |
|
3751 } |
|
3752 // Nothing need be done for the normal startup case. |
|
3753 } |
|
3754 else { |
|
3755 // Remove caches, forcing component re-registration |
|
3756 // with the default set of components (this disables any potentially |
|
3757 // troublesome incompatible XPCOM components). |
|
3758 startupCacheValid = RemoveComponentRegistries(mProfD, mProfLD, true); |
|
3759 |
|
3760 // Write out version |
|
3761 WriteVersion(mProfD, version, osABI, |
|
3762 mDirProvider.GetGREDir(), mAppData->directory, !startupCacheValid); |
|
3763 } |
|
3764 |
|
3765 if (!startupCacheValid) |
|
3766 StartupCache::IgnoreDiskCache(); |
|
3767 |
|
3768 if (flagFile) { |
|
3769 flagFile->Remove(true); |
|
3770 } |
|
3771 |
|
3772 return 0; |
|
3773 } |
|
3774 |
|
3775 /* |
|
3776 * XRE_mainRun - Command line startup, profile migration, and |
|
3777 * the calling of appStartup->Run(). |
|
3778 */ |
|
3779 nsresult |
|
3780 XREMain::XRE_mainRun() |
|
3781 { |
|
3782 nsresult rv = NS_OK; |
|
3783 NS_ASSERTION(mScopedXPCom, "Scoped xpcom not initialized."); |
|
3784 |
|
3785 #ifdef NS_FUNCTION_TIMER |
|
3786 // initialize some common services, so we don't pay the cost for these at odd times later on; |
|
3787 // SetWindowCreator -> ChromeRegistry -> IOService -> SocketTransportService -> (nspr wspm init), Prefs |
|
3788 { |
|
3789 nsCOMPtr<nsISupports> comp; |
|
3790 |
|
3791 comp = do_GetService("@mozilla.org/preferences-service;1"); |
|
3792 |
|
3793 comp = do_GetService("@mozilla.org/network/socket-transport-service;1"); |
|
3794 |
|
3795 comp = do_GetService("@mozilla.org/network/dns-service;1"); |
|
3796 |
|
3797 comp = do_GetService("@mozilla.org/network/io-service;1"); |
|
3798 |
|
3799 comp = do_GetService("@mozilla.org/chrome/chrome-registry;1"); |
|
3800 |
|
3801 comp = do_GetService("@mozilla.org/focus-event-suppressor-service;1"); |
|
3802 } |
|
3803 #endif |
|
3804 |
|
3805 rv = mScopedXPCom->SetWindowCreator(mNativeApp); |
|
3806 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); |
|
3807 |
|
3808 #ifdef MOZ_CRASHREPORTER |
|
3809 // tell the crash reporter to also send the release channel |
|
3810 nsCOMPtr<nsIPrefService> prefs = do_GetService("@mozilla.org/preferences-service;1", &rv); |
|
3811 if (NS_SUCCEEDED(rv)) { |
|
3812 nsCOMPtr<nsIPrefBranch> defaultPrefBranch; |
|
3813 rv = prefs->GetDefaultBranch(nullptr, getter_AddRefs(defaultPrefBranch)); |
|
3814 |
|
3815 if (NS_SUCCEEDED(rv)) { |
|
3816 nsXPIDLCString sval; |
|
3817 rv = defaultPrefBranch->GetCharPref("app.update.channel", getter_Copies(sval)); |
|
3818 if (NS_SUCCEEDED(rv)) { |
|
3819 CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("ReleaseChannel"), |
|
3820 sval); |
|
3821 } |
|
3822 } |
|
3823 } |
|
3824 // Needs to be set after xpcom initialization. |
|
3825 CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("FramePoisonBase"), |
|
3826 nsPrintfCString("%.16llx", uint64_t(gMozillaPoisonBase))); |
|
3827 CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("FramePoisonSize"), |
|
3828 nsPrintfCString("%lu", uint32_t(gMozillaPoisonSize))); |
|
3829 |
|
3830 #ifdef XP_WIN |
|
3831 PR_CreateThread(PR_USER_THREAD, AnnotateSystemManufacturer_ThreadStart, 0, |
|
3832 PR_PRIORITY_LOW, PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD, 0); |
|
3833 #endif |
|
3834 |
|
3835 #endif |
|
3836 |
|
3837 if (mStartOffline) { |
|
3838 nsCOMPtr<nsIIOService2> io (do_GetService("@mozilla.org/network/io-service;1")); |
|
3839 NS_ENSURE_TRUE(io, NS_ERROR_FAILURE); |
|
3840 io->SetManageOfflineStatus(false); |
|
3841 io->SetOffline(true); |
|
3842 } |
|
3843 |
|
3844 { |
|
3845 nsCOMPtr<nsIObserver> startupNotifier |
|
3846 (do_CreateInstance(NS_APPSTARTUPNOTIFIER_CONTRACTID, &rv)); |
|
3847 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); |
|
3848 |
|
3849 startupNotifier->Observe(nullptr, APPSTARTUP_TOPIC, nullptr); |
|
3850 } |
|
3851 |
|
3852 nsCOMPtr<nsIAppStartup> appStartup |
|
3853 (do_GetService(NS_APPSTARTUP_CONTRACTID)); |
|
3854 NS_ENSURE_TRUE(appStartup, NS_ERROR_FAILURE); |
|
3855 |
|
3856 if (gDoMigration) { |
|
3857 nsCOMPtr<nsIFile> file; |
|
3858 mDirProvider.GetAppDir()->Clone(getter_AddRefs(file)); |
|
3859 file->AppendNative(NS_LITERAL_CSTRING("override.ini")); |
|
3860 nsINIParser parser; |
|
3861 nsresult rv = parser.Init(file); |
|
3862 if (NS_SUCCEEDED(rv)) { |
|
3863 nsAutoCString buf; |
|
3864 rv = parser.GetString("XRE", "EnableProfileMigrator", buf); |
|
3865 if (NS_SUCCEEDED(rv)) { |
|
3866 if (buf[0] == '0' || buf[0] == 'f' || buf[0] == 'F') { |
|
3867 gDoMigration = false; |
|
3868 } |
|
3869 } |
|
3870 } |
|
3871 } |
|
3872 |
|
3873 { |
|
3874 nsCOMPtr<nsIToolkitProfile> selectedProfile; |
|
3875 if (gDoProfileReset) { |
|
3876 // At this point we can be sure that profile reset is happening on the default profile. |
|
3877 rv = mProfileSvc->GetSelectedProfile(getter_AddRefs(selectedProfile)); |
|
3878 if (NS_FAILED(rv)) { |
|
3879 gDoProfileReset = false; |
|
3880 return NS_ERROR_FAILURE; |
|
3881 } |
|
3882 } |
|
3883 |
|
3884 // Profile Migration |
|
3885 if (mAppData->flags & NS_XRE_ENABLE_PROFILE_MIGRATOR && gDoMigration) { |
|
3886 gDoMigration = false; |
|
3887 nsCOMPtr<nsIProfileMigrator> pm(do_CreateInstance(NS_PROFILEMIGRATOR_CONTRACTID)); |
|
3888 if (pm) { |
|
3889 nsAutoCString aKey; |
|
3890 if (gDoProfileReset) { |
|
3891 // Automatically migrate from the current application if we just |
|
3892 // reset the profile. |
|
3893 aKey = MOZ_APP_NAME; |
|
3894 } |
|
3895 pm->Migrate(&mDirProvider, aKey); |
|
3896 } |
|
3897 } |
|
3898 |
|
3899 if (gDoProfileReset) { |
|
3900 nsresult backupCreated = ProfileResetCleanup(selectedProfile); |
|
3901 if (NS_FAILED(backupCreated)) NS_WARNING("Could not cleanup the profile that was reset"); |
|
3902 |
|
3903 // Set the new profile as the default after we're done cleaning up the old default. |
|
3904 rv = SetCurrentProfileAsDefault(mProfileSvc, mProfD); |
|
3905 if (NS_FAILED(rv)) NS_WARNING("Could not set current profile as the default"); |
|
3906 } |
|
3907 } |
|
3908 |
|
3909 mDirProvider.DoStartup(); |
|
3910 |
|
3911 #ifdef MOZ_CRASHREPORTER |
|
3912 nsCString userAgentLocale; |
|
3913 if (NS_SUCCEEDED(Preferences::GetCString("general.useragent.locale", &userAgentLocale))) { |
|
3914 CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("useragent_locale"), userAgentLocale); |
|
3915 } |
|
3916 #endif |
|
3917 |
|
3918 appStartup->GetShuttingDown(&mShuttingDown); |
|
3919 |
|
3920 nsCOMPtr<nsICommandLineRunner> cmdLine; |
|
3921 |
|
3922 nsCOMPtr<nsIFile> workingDir; |
|
3923 rv = NS_GetSpecialDirectory(NS_OS_CURRENT_WORKING_DIR, getter_AddRefs(workingDir)); |
|
3924 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); |
|
3925 |
|
3926 if (!mShuttingDown) { |
|
3927 cmdLine = do_CreateInstance("@mozilla.org/toolkit/command-line;1"); |
|
3928 NS_ENSURE_TRUE(cmdLine, NS_ERROR_FAILURE); |
|
3929 |
|
3930 rv = cmdLine->Init(gArgc, gArgv, workingDir, |
|
3931 nsICommandLine::STATE_INITIAL_LAUNCH); |
|
3932 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); |
|
3933 |
|
3934 /* Special-case services that need early access to the command |
|
3935 line. */ |
|
3936 nsCOMPtr<nsIObserverService> obsService = |
|
3937 mozilla::services::GetObserverService(); |
|
3938 if (obsService) { |
|
3939 obsService->NotifyObservers(cmdLine, "command-line-startup", nullptr); |
|
3940 } |
|
3941 } |
|
3942 |
|
3943 SaveStateForAppInitiatedRestart(); |
|
3944 |
|
3945 // clear out any environment variables which may have been set |
|
3946 // during the relaunch process now that we know we won't be relaunching. |
|
3947 SaveToEnv("XRE_PROFILE_PATH="); |
|
3948 SaveToEnv("XRE_PROFILE_LOCAL_PATH="); |
|
3949 SaveToEnv("XRE_PROFILE_NAME="); |
|
3950 SaveToEnv("XRE_START_OFFLINE="); |
|
3951 SaveToEnv("NO_EM_RESTART="); |
|
3952 SaveToEnv("XUL_APP_FILE="); |
|
3953 SaveToEnv("XRE_BINARY_PATH="); |
|
3954 |
|
3955 if (!mShuttingDown) { |
|
3956 rv = appStartup->CreateHiddenWindow(); |
|
3957 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); |
|
3958 |
|
3959 #if defined(HAVE_DESKTOP_STARTUP_ID) && defined(MOZ_WIDGET_GTK) |
|
3960 nsGTKToolkit* toolkit = nsGTKToolkit::GetToolkit(); |
|
3961 if (toolkit && !mDesktopStartupID.IsEmpty()) { |
|
3962 toolkit->SetDesktopStartupID(mDesktopStartupID); |
|
3963 } |
|
3964 // Clear the environment variable so it won't be inherited by |
|
3965 // child processes and confuse things. |
|
3966 g_unsetenv ("DESKTOP_STARTUP_ID"); |
|
3967 #endif |
|
3968 |
|
3969 #ifdef XP_MACOSX |
|
3970 // Set up ability to respond to system (Apple) events. This must be |
|
3971 // done before setting up the command line service. |
|
3972 SetupMacApplicationDelegate(); |
|
3973 |
|
3974 // we re-initialize the command-line service and do appleevents munging |
|
3975 // after we are sure that we're not restarting |
|
3976 cmdLine = do_CreateInstance("@mozilla.org/toolkit/command-line;1"); |
|
3977 NS_ENSURE_TRUE(cmdLine, NS_ERROR_FAILURE); |
|
3978 |
|
3979 CommandLineServiceMac::SetupMacCommandLine(gArgc, gArgv, false); |
|
3980 |
|
3981 rv = cmdLine->Init(gArgc, gArgv, |
|
3982 workingDir, nsICommandLine::STATE_INITIAL_LAUNCH); |
|
3983 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); |
|
3984 #endif |
|
3985 |
|
3986 nsCOMPtr<nsIObserverService> obsService = |
|
3987 mozilla::services::GetObserverService(); |
|
3988 if (obsService) |
|
3989 obsService->NotifyObservers(nullptr, "final-ui-startup", nullptr); |
|
3990 |
|
3991 (void)appStartup->DoneStartingUp(); |
|
3992 appStartup->GetShuttingDown(&mShuttingDown); |
|
3993 } |
|
3994 |
|
3995 if (!mShuttingDown) { |
|
3996 rv = cmdLine->Run(); |
|
3997 NS_ENSURE_SUCCESS_LOG(rv, NS_ERROR_FAILURE); |
|
3998 |
|
3999 appStartup->GetShuttingDown(&mShuttingDown); |
|
4000 } |
|
4001 |
|
4002 if (!mShuttingDown) { |
|
4003 #ifdef MOZ_ENABLE_XREMOTE |
|
4004 // if we have X remote support, start listening for requests on the |
|
4005 // proxy window. |
|
4006 if (!mDisableRemote) |
|
4007 mRemoteService = do_GetService("@mozilla.org/toolkit/remote-service;1"); |
|
4008 if (mRemoteService) |
|
4009 mRemoteService->Startup(mAppData->name, mProfileName.get()); |
|
4010 #endif /* MOZ_ENABLE_XREMOTE */ |
|
4011 |
|
4012 mNativeApp->Enable(); |
|
4013 } |
|
4014 |
|
4015 #ifdef MOZ_INSTRUMENT_EVENT_LOOP |
|
4016 if (PR_GetEnv("MOZ_INSTRUMENT_EVENT_LOOP") || profiler_is_active()) { |
|
4017 bool logToConsole = !!PR_GetEnv("MOZ_INSTRUMENT_EVENT_LOOP"); |
|
4018 mozilla::InitEventTracing(logToConsole); |
|
4019 } |
|
4020 #endif /* MOZ_INSTRUMENT_EVENT_LOOP */ |
|
4021 |
|
4022 { |
|
4023 rv = appStartup->Run(); |
|
4024 if (NS_FAILED(rv)) { |
|
4025 NS_ERROR("failed to run appstartup"); |
|
4026 gLogConsoleErrors = true; |
|
4027 } |
|
4028 } |
|
4029 |
|
4030 return rv; |
|
4031 } |
|
4032 |
|
4033 /* |
|
4034 * XRE_main - A class based main entry point used by most platforms. |
|
4035 */ |
|
4036 int |
|
4037 XREMain::XRE_main(int argc, char* argv[], const nsXREAppData* aAppData) |
|
4038 { |
|
4039 char aLocal; |
|
4040 GeckoProfilerInitRAII profilerGuard(&aLocal); |
|
4041 PROFILER_LABEL("Startup", "XRE_Main"); |
|
4042 |
|
4043 mozilla::IOInterposerInit ioInterposerGuard; |
|
4044 |
|
4045 nsresult rv = NS_OK; |
|
4046 |
|
4047 gArgc = argc; |
|
4048 gArgv = argv; |
|
4049 |
|
4050 NS_ENSURE_TRUE(aAppData, 2); |
|
4051 |
|
4052 mAppData = new ScopedAppData(aAppData); |
|
4053 if (!mAppData) |
|
4054 return 1; |
|
4055 // used throughout this file |
|
4056 gAppData = mAppData; |
|
4057 |
|
4058 ScopedLogging log; |
|
4059 |
|
4060 #if defined(MOZ_WIDGET_GTK) |
|
4061 #if defined(MOZ_MEMORY) || defined(__FreeBSD__) || defined(__NetBSD__) |
|
4062 // Disable the slice allocator, since jemalloc already uses similar layout |
|
4063 // algorithms, and using a sub-allocator tends to increase fragmentation. |
|
4064 // This must be done before g_thread_init() is called. |
|
4065 g_slice_set_config(G_SLICE_CONFIG_ALWAYS_MALLOC, 1); |
|
4066 #endif |
|
4067 g_thread_init(nullptr); |
|
4068 #endif |
|
4069 |
|
4070 // init |
|
4071 bool exit = false; |
|
4072 int result = XRE_mainInit(&exit); |
|
4073 if (result != 0 || exit) |
|
4074 return result; |
|
4075 |
|
4076 // startup |
|
4077 result = XRE_mainStartup(&exit); |
|
4078 if (result != 0 || exit) |
|
4079 return result; |
|
4080 |
|
4081 bool appInitiatedRestart = false; |
|
4082 |
|
4083 // Start the real application |
|
4084 mScopedXPCom = new ScopedXPCOMStartup(); |
|
4085 if (!mScopedXPCom) |
|
4086 return 1; |
|
4087 |
|
4088 rv = mScopedXPCom->Initialize(); |
|
4089 NS_ENSURE_SUCCESS(rv, 1); |
|
4090 |
|
4091 // run! |
|
4092 rv = XRE_mainRun(); |
|
4093 |
|
4094 #ifdef MOZ_INSTRUMENT_EVENT_LOOP |
|
4095 mozilla::ShutdownEventTracing(); |
|
4096 #endif |
|
4097 |
|
4098 // Check for an application initiated restart. This is one that |
|
4099 // corresponds to nsIAppStartup.quit(eRestart) |
|
4100 if (rv == NS_SUCCESS_RESTART_APP || rv == NS_SUCCESS_RESTART_METRO_APP) { |
|
4101 appInitiatedRestart = true; |
|
4102 |
|
4103 // We have an application restart don't do any shutdown checks here |
|
4104 // In particular we don't want to poison IO for checking late-writes. |
|
4105 gShutdownChecks = SCM_NOTHING; |
|
4106 } |
|
4107 |
|
4108 if (!mShuttingDown) { |
|
4109 #ifdef MOZ_ENABLE_XREMOTE |
|
4110 // shut down the x remote proxy window |
|
4111 if (mRemoteService) { |
|
4112 mRemoteService->Shutdown(); |
|
4113 } |
|
4114 #endif /* MOZ_ENABLE_XREMOTE */ |
|
4115 } |
|
4116 |
|
4117 delete mScopedXPCom; |
|
4118 mScopedXPCom = nullptr; |
|
4119 |
|
4120 // unlock the profile after ScopedXPCOMStartup object (xpcom) |
|
4121 // has gone out of scope. see bug #386739 for more details |
|
4122 mProfileLock->Unlock(); |
|
4123 gProfileLock = nullptr; |
|
4124 |
|
4125 #if defined(MOZ_WIDGET_QT) |
|
4126 nsQAppInstance::Release(); |
|
4127 #endif |
|
4128 |
|
4129 // Restart the app after XPCOM has been shut down cleanly. |
|
4130 if (appInitiatedRestart) { |
|
4131 RestoreStateForAppInitiatedRestart(); |
|
4132 |
|
4133 // Ensure that these environment variables are set: |
|
4134 SaveFileToEnvIfUnset("XRE_PROFILE_PATH", mProfD); |
|
4135 SaveFileToEnvIfUnset("XRE_PROFILE_LOCAL_PATH", mProfLD); |
|
4136 SaveWordToEnvIfUnset("XRE_PROFILE_NAME", mProfileName); |
|
4137 |
|
4138 #ifdef MOZ_WIDGET_GTK |
|
4139 MOZ_gdk_display_close(mGdkDisplay); |
|
4140 #endif |
|
4141 |
|
4142 #if defined(MOZ_METRO) && defined(XP_WIN) |
|
4143 if (rv == NS_SUCCESS_RESTART_METRO_APP) { |
|
4144 LaunchDefaultMetroBrowser(); |
|
4145 rv = NS_OK; |
|
4146 } else |
|
4147 #endif |
|
4148 { |
|
4149 rv = LaunchChild(mNativeApp, true); |
|
4150 } |
|
4151 |
|
4152 #ifdef MOZ_CRASHREPORTER |
|
4153 if (mAppData->flags & NS_XRE_ENABLE_CRASH_REPORTER) |
|
4154 CrashReporter::UnsetExceptionHandler(); |
|
4155 #endif |
|
4156 return rv == NS_ERROR_LAUNCHED_CHILD_PROCESS ? 0 : 1; |
|
4157 } |
|
4158 |
|
4159 #ifdef MOZ_WIDGET_GTK |
|
4160 // gdk_display_close also calls gdk_display_manager_set_default_display |
|
4161 // appropriately when necessary. |
|
4162 MOZ_gdk_display_close(mGdkDisplay); |
|
4163 #endif |
|
4164 |
|
4165 #ifdef MOZ_CRASHREPORTER |
|
4166 if (mAppData->flags & NS_XRE_ENABLE_CRASH_REPORTER) |
|
4167 CrashReporter::UnsetExceptionHandler(); |
|
4168 #endif |
|
4169 |
|
4170 XRE_DeinitCommandLine(); |
|
4171 |
|
4172 return NS_FAILED(rv) ? 1 : 0; |
|
4173 } |
|
4174 |
|
4175 #if defined(MOZ_METRO) && defined(XP_WIN) |
|
4176 extern bool XRE_MetroCoreApplicationRun(); |
|
4177 static XREMain* xreMainPtr; |
|
4178 |
|
4179 // must be called by the thread we want as the main thread |
|
4180 nsresult |
|
4181 XRE_metroStartup(bool runXREMain) |
|
4182 { |
|
4183 nsresult rv; |
|
4184 |
|
4185 bool exit = false; |
|
4186 if (xreMainPtr->XRE_mainStartup(&exit) != 0 || exit) |
|
4187 return NS_ERROR_FAILURE; |
|
4188 |
|
4189 // Start the real application |
|
4190 xreMainPtr->mScopedXPCom = new ScopedXPCOMStartup(); |
|
4191 if (!xreMainPtr->mScopedXPCom) |
|
4192 return NS_ERROR_FAILURE; |
|
4193 |
|
4194 rv = xreMainPtr->mScopedXPCom->Initialize(); |
|
4195 NS_ENSURE_SUCCESS(rv, rv); |
|
4196 |
|
4197 if (runXREMain) { |
|
4198 rv = xreMainPtr->XRE_mainRun(); |
|
4199 NS_ENSURE_SUCCESS(rv, rv); |
|
4200 } |
|
4201 return NS_OK; |
|
4202 } |
|
4203 |
|
4204 void |
|
4205 XRE_metroShutdown() |
|
4206 { |
|
4207 delete xreMainPtr->mScopedXPCom; |
|
4208 xreMainPtr->mScopedXPCom = nullptr; |
|
4209 |
|
4210 #ifdef MOZ_INSTRUMENT_EVENT_LOOP |
|
4211 mozilla::ShutdownEventTracing(); |
|
4212 #endif |
|
4213 |
|
4214 // unlock the profile after ScopedXPCOMStartup object (xpcom) |
|
4215 // has gone out of scope. see bug #386739 for more details |
|
4216 xreMainPtr->mProfileLock->Unlock(); |
|
4217 gProfileLock = nullptr; |
|
4218 |
|
4219 #ifdef MOZ_CRASHREPORTER |
|
4220 if (xreMainPtr->mAppData->flags & NS_XRE_ENABLE_CRASH_REPORTER) |
|
4221 CrashReporter::UnsetExceptionHandler(); |
|
4222 #endif |
|
4223 |
|
4224 XRE_DeinitCommandLine(); |
|
4225 } |
|
4226 |
|
4227 class WinRTInitWrapper |
|
4228 { |
|
4229 public: |
|
4230 WinRTInitWrapper() { |
|
4231 mResult = ::RoInitialize(RO_INIT_MULTITHREADED); |
|
4232 } |
|
4233 ~WinRTInitWrapper() { |
|
4234 if (SUCCEEDED(mResult)) { |
|
4235 ::RoUninitialize(); |
|
4236 } |
|
4237 } |
|
4238 HRESULT mResult; |
|
4239 }; |
|
4240 |
|
4241 int |
|
4242 XRE_mainMetro(int argc, char* argv[], const nsXREAppData* aAppData) |
|
4243 { |
|
4244 char aLocal; |
|
4245 GeckoProfilerInitRAII profilerGuard(&aLocal); |
|
4246 PROFILER_LABEL("Startup", "XRE_Main"); |
|
4247 |
|
4248 mozilla::IOInterposerInit ioInterposerGuard; |
|
4249 |
|
4250 nsresult rv = NS_OK; |
|
4251 |
|
4252 xreMainPtr = new XREMain(); |
|
4253 if (!xreMainPtr) { |
|
4254 return 1; |
|
4255 } |
|
4256 |
|
4257 // Inits Winrt and COM underneath it. |
|
4258 WinRTInitWrapper wrap; |
|
4259 |
|
4260 gArgc = argc; |
|
4261 gArgv = argv; |
|
4262 |
|
4263 NS_ENSURE_TRUE(aAppData, 2); |
|
4264 |
|
4265 xreMainPtr->mAppData = new ScopedAppData(aAppData); |
|
4266 if (!xreMainPtr->mAppData) |
|
4267 return 1; |
|
4268 // used throughout this file |
|
4269 gAppData = xreMainPtr->mAppData; |
|
4270 |
|
4271 ScopedLogging log; |
|
4272 |
|
4273 // init |
|
4274 bool exit = false; |
|
4275 if (xreMainPtr->XRE_mainInit(&exit) != 0 || exit) |
|
4276 return 1; |
|
4277 |
|
4278 // Located in widget, will call back into XRE_metroStartup and |
|
4279 // XRE_metroShutdown above. |
|
4280 if (!XRE_MetroCoreApplicationRun()) { |
|
4281 return 1; |
|
4282 } |
|
4283 |
|
4284 // XRE_metroShutdown should have already been called on the worker |
|
4285 // thread that called XRE_metroStartup. |
|
4286 NS_ASSERTION(!xreMainPtr->mScopedXPCom, |
|
4287 "XPCOM Shutdown hasn't occured, and we are exiting."); |
|
4288 return 0; |
|
4289 } |
|
4290 |
|
4291 void SetWindowsEnvironment(WindowsEnvironmentType aEnvID); |
|
4292 #endif // MOZ_METRO || !defined(XP_WIN) |
|
4293 |
|
4294 void |
|
4295 XRE_StopLateWriteChecks(void) { |
|
4296 mozilla::StopLateWriteChecks(); |
|
4297 } |
|
4298 |
|
4299 int |
|
4300 XRE_main(int argc, char* argv[], const nsXREAppData* aAppData, uint32_t aFlags) |
|
4301 { |
|
4302 #if !defined(MOZ_METRO) || !defined(XP_WIN) |
|
4303 XREMain main; |
|
4304 int result = main.XRE_main(argc, argv, aAppData); |
|
4305 mozilla::RecordShutdownEndTimeStamp(); |
|
4306 return result; |
|
4307 #else |
|
4308 if (aFlags == XRE_MAIN_FLAG_USE_METRO) { |
|
4309 SetWindowsEnvironment(WindowsEnvironmentType_Metro); |
|
4310 } |
|
4311 |
|
4312 // Desktop |
|
4313 if (XRE_GetWindowsEnvironment() == WindowsEnvironmentType_Desktop) { |
|
4314 XREMain main; |
|
4315 int result = main.XRE_main(argc, argv, aAppData); |
|
4316 mozilla::RecordShutdownEndTimeStamp(); |
|
4317 return result; |
|
4318 } |
|
4319 |
|
4320 // Metro |
|
4321 NS_ASSERTION(XRE_GetWindowsEnvironment() == WindowsEnvironmentType_Metro, |
|
4322 "Unknown Windows environment"); |
|
4323 |
|
4324 SetLastWinRunType(AHE_IMMERSIVE); |
|
4325 |
|
4326 int result = XRE_mainMetro(argc, argv, aAppData); |
|
4327 mozilla::RecordShutdownEndTimeStamp(); |
|
4328 return result; |
|
4329 #endif // MOZ_METRO || !defined(XP_WIN) |
|
4330 } |
|
4331 |
|
4332 nsresult |
|
4333 XRE_InitCommandLine(int aArgc, char* aArgv[]) |
|
4334 { |
|
4335 nsresult rv = NS_OK; |
|
4336 |
|
4337 #if defined(OS_WIN) |
|
4338 CommandLine::Init(aArgc, aArgv); |
|
4339 #else |
|
4340 |
|
4341 // these leak on error, but that's OK: we'll just exit() |
|
4342 char** canonArgs = new char*[aArgc]; |
|
4343 |
|
4344 // get the canonical version of the binary's path |
|
4345 nsCOMPtr<nsIFile> binFile; |
|
4346 rv = XRE_GetBinaryPath(aArgv[0], getter_AddRefs(binFile)); |
|
4347 if (NS_FAILED(rv)) |
|
4348 return NS_ERROR_FAILURE; |
|
4349 |
|
4350 nsAutoCString canonBinPath; |
|
4351 rv = binFile->GetNativePath(canonBinPath); |
|
4352 if (NS_FAILED(rv)) |
|
4353 return NS_ERROR_FAILURE; |
|
4354 |
|
4355 canonArgs[0] = strdup(canonBinPath.get()); |
|
4356 |
|
4357 for (int i = 1; i < aArgc; ++i) { |
|
4358 if (aArgv[i]) { |
|
4359 canonArgs[i] = strdup(aArgv[i]); |
|
4360 } |
|
4361 } |
|
4362 |
|
4363 NS_ASSERTION(!CommandLine::IsInitialized(), "Bad news!"); |
|
4364 CommandLine::Init(aArgc, canonArgs); |
|
4365 |
|
4366 for (int i = 0; i < aArgc; ++i) |
|
4367 free(canonArgs[i]); |
|
4368 delete[] canonArgs; |
|
4369 #endif |
|
4370 |
|
4371 const char *path = nullptr; |
|
4372 ArgResult ar = CheckArg("greomni", false, &path); |
|
4373 if (ar == ARG_BAD) { |
|
4374 PR_fprintf(PR_STDERR, "Error: argument -greomni requires a path argument\n"); |
|
4375 return NS_ERROR_FAILURE; |
|
4376 } |
|
4377 |
|
4378 if (!path) |
|
4379 return rv; |
|
4380 |
|
4381 nsCOMPtr<nsIFile> greOmni; |
|
4382 rv = XRE_GetFileFromPath(path, getter_AddRefs(greOmni)); |
|
4383 if (NS_FAILED(rv)) { |
|
4384 PR_fprintf(PR_STDERR, "Error: argument -greomni requires a valid path\n"); |
|
4385 return rv; |
|
4386 } |
|
4387 |
|
4388 ar = CheckArg("appomni", false, &path); |
|
4389 if (ar == ARG_BAD) { |
|
4390 PR_fprintf(PR_STDERR, "Error: argument -appomni requires a path argument\n"); |
|
4391 return NS_ERROR_FAILURE; |
|
4392 } |
|
4393 |
|
4394 nsCOMPtr<nsIFile> appOmni; |
|
4395 if (path) { |
|
4396 rv = XRE_GetFileFromPath(path, getter_AddRefs(appOmni)); |
|
4397 if (NS_FAILED(rv)) { |
|
4398 PR_fprintf(PR_STDERR, "Error: argument -appomni requires a valid path\n"); |
|
4399 return rv; |
|
4400 } |
|
4401 } |
|
4402 |
|
4403 mozilla::Omnijar::Init(greOmni, appOmni); |
|
4404 return rv; |
|
4405 } |
|
4406 |
|
4407 nsresult |
|
4408 XRE_DeinitCommandLine() |
|
4409 { |
|
4410 nsresult rv = NS_OK; |
|
4411 |
|
4412 CommandLine::Terminate(); |
|
4413 |
|
4414 return rv; |
|
4415 } |
|
4416 |
|
4417 GeckoProcessType |
|
4418 XRE_GetProcessType() |
|
4419 { |
|
4420 return mozilla::startup::sChildProcessType; |
|
4421 } |
|
4422 |
|
4423 bool |
|
4424 mozilla::BrowserTabsRemote() |
|
4425 { |
|
4426 if (!gBrowserTabsRemoteInitialized) { |
|
4427 gBrowserTabsRemote = Preferences::GetBool("browser.tabs.remote", false); |
|
4428 gBrowserTabsRemoteInitialized = true; |
|
4429 } |
|
4430 |
|
4431 return gBrowserTabsRemote; |
|
4432 } |
|
4433 |
|
4434 void |
|
4435 SetupErrorHandling(const char* progname) |
|
4436 { |
|
4437 #ifdef XP_WIN |
|
4438 /* On Windows XPSP3 and Windows Vista if DEP is configured off-by-default |
|
4439 we still want DEP protection: enable it explicitly and programmatically. |
|
4440 |
|
4441 This function is not available on WinXPSP2 so we dynamically load it. |
|
4442 */ |
|
4443 |
|
4444 HMODULE kernel32 = GetModuleHandleW(L"kernel32.dll"); |
|
4445 SetProcessDEPPolicyFunc _SetProcessDEPPolicy = |
|
4446 (SetProcessDEPPolicyFunc) GetProcAddress(kernel32, "SetProcessDEPPolicy"); |
|
4447 if (_SetProcessDEPPolicy) |
|
4448 _SetProcessDEPPolicy(PROCESS_DEP_ENABLE); |
|
4449 #endif |
|
4450 |
|
4451 #ifdef XP_WIN32 |
|
4452 // Suppress the "DLL Foo could not be found" dialog, such that if dependent |
|
4453 // libraries (such as GDI+) are not preset, we gracefully fail to load those |
|
4454 // XPCOM components, instead of being ungraceful. |
|
4455 UINT realMode = SetErrorMode(0); |
|
4456 realMode |= SEM_FAILCRITICALERRORS; |
|
4457 // If XRE_NO_WINDOWS_CRASH_DIALOG is set, suppress displaying the "This |
|
4458 // application has crashed" dialog box. This is mainly useful for |
|
4459 // automated testing environments, e.g. tinderbox, where there's no need |
|
4460 // for a dozen of the dialog boxes to litter the console |
|
4461 if (getenv("XRE_NO_WINDOWS_CRASH_DIALOG")) |
|
4462 realMode |= SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX; |
|
4463 |
|
4464 SetErrorMode(realMode); |
|
4465 |
|
4466 #endif |
|
4467 |
|
4468 #if defined (DEBUG) && defined(XP_WIN) |
|
4469 // Send MSCRT Warnings, Errors and Assertions to stderr. |
|
4470 // See http://msdn.microsoft.com/en-us/library/1y71x448(v=VS.80).aspx |
|
4471 // and http://msdn.microsoft.com/en-us/library/a68f826y(v=VS.80).aspx. |
|
4472 |
|
4473 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE); |
|
4474 _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR); |
|
4475 _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE); |
|
4476 _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR); |
|
4477 _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE); |
|
4478 _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR); |
|
4479 |
|
4480 _CrtSetReportHook(MSCRTReportHook); |
|
4481 #endif |
|
4482 |
|
4483 InstallSignalHandlers(progname); |
|
4484 |
|
4485 // Unbuffer stdout, needed for tinderbox tests. |
|
4486 setbuf(stdout, 0); |
|
4487 } |
|
4488 |