/src/mozilla-central/toolkit/xre/nsAppRunner.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
3 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
4 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
5 | | |
6 | | #include "mozilla/dom/ContentParent.h" |
7 | | #include "mozilla/dom/ContentChild.h" |
8 | | #include "mozilla/ipc/GeckoChildProcessHost.h" |
9 | | |
10 | | #include "mozilla/ArrayUtils.h" |
11 | | #include "mozilla/Attributes.h" |
12 | | #include "mozilla/FilePreferences.h" |
13 | | #include "mozilla/ChaosMode.h" |
14 | | #include "mozilla/CmdLineAndEnvUtils.h" |
15 | | #include "mozilla/IOInterposer.h" |
16 | | #include "mozilla/Likely.h" |
17 | | #include "mozilla/MemoryChecking.h" |
18 | | #include "mozilla/Poison.h" |
19 | | #include "mozilla/Preferences.h" |
20 | | #include "mozilla/Printf.h" |
21 | | #include "mozilla/ResultExtensions.h" |
22 | | #include "mozilla/ScopeExit.h" |
23 | | #include "mozilla/Services.h" |
24 | | #include "mozilla/Telemetry.h" |
25 | | #include "mozilla/intl/LocaleService.h" |
26 | | #include "mozilla/recordreplay/ParentIPC.h" |
27 | | |
28 | | #include "nsAppRunner.h" |
29 | | #include "mozilla/XREAppData.h" |
30 | | #include "mozilla/Bootstrap.h" |
31 | | #if defined(MOZ_UPDATER) && !defined(MOZ_WIDGET_ANDROID) |
32 | | #include "nsUpdateDriver.h" |
33 | | #endif |
34 | | #include "ProfileReset.h" |
35 | | |
36 | | #ifdef MOZ_INSTRUMENT_EVENT_LOOP |
37 | | #include "EventTracer.h" |
38 | | #endif |
39 | | |
40 | | #ifdef XP_MACOSX |
41 | | #include "nsVersionComparator.h" |
42 | | #include "MacLaunchHelper.h" |
43 | | #include "MacApplicationDelegate.h" |
44 | | #include "MacAutoreleasePool.h" |
45 | | // these are needed for sysctl |
46 | | #include <sys/types.h> |
47 | | #include <sys/sysctl.h> |
48 | | #endif |
49 | | |
50 | | #include "prnetdb.h" |
51 | | #include "prprf.h" |
52 | | #include "prproces.h" |
53 | | #include "prenv.h" |
54 | | #include "prtime.h" |
55 | | |
56 | | #include "nsIAppShellService.h" |
57 | | #include "nsIAppStartup.h" |
58 | | #include "nsAppStartupNotifier.h" |
59 | | #include "nsIMutableArray.h" |
60 | | #include "nsICategoryManager.h" |
61 | | #include "nsIChromeRegistry.h" |
62 | | #include "nsCommandLine.h" |
63 | | #include "nsIComponentManager.h" |
64 | | #include "nsIComponentRegistrar.h" |
65 | | #include "nsIConsoleService.h" |
66 | | #include "nsIContentHandler.h" |
67 | | #include "nsIDialogParamBlock.h" |
68 | | #include "nsIDOMWindow.h" |
69 | | #include "mozilla/ModuleUtils.h" |
70 | | #include "nsIIOService.h" |
71 | | #include "nsIObserverService.h" |
72 | | #include "nsINativeAppSupport.h" |
73 | | #include "nsIPlatformInfo.h" |
74 | | #include "nsIProcess.h" |
75 | | #include "nsIProfileUnlocker.h" |
76 | | #include "nsIPromptService.h" |
77 | | #include "nsIServiceManager.h" |
78 | | #include "nsIStringBundle.h" |
79 | | #include "nsISupportsPrimitives.h" |
80 | | #include "nsIToolkitChromeRegistry.h" |
81 | | #include "nsIToolkitProfile.h" |
82 | | #include "nsIToolkitProfileService.h" |
83 | | #include "nsIURI.h" |
84 | | #include "nsIURL.h" |
85 | | #include "nsIWindowCreator.h" |
86 | | #include "nsIWindowMediator.h" |
87 | | #include "nsIWindowWatcher.h" |
88 | | #include "nsIXULAppInfo.h" |
89 | | #include "nsIXULRuntime.h" |
90 | | #include "nsPIDOMWindow.h" |
91 | | #include "nsIBaseWindow.h" |
92 | | #include "nsIWidget.h" |
93 | | #include "nsIDocShell.h" |
94 | | #include "nsAppShellCID.h" |
95 | | #include "mozilla/scache/StartupCache.h" |
96 | | #include "gfxPlatform.h" |
97 | | #include "gfxPrefs.h" |
98 | | |
99 | | #include "mozilla/Unused.h" |
100 | | |
101 | | #ifdef XP_WIN |
102 | | #include "nsIWinAppHelper.h" |
103 | | #include <windows.h> |
104 | | #include <intrin.h> |
105 | | #include <math.h> |
106 | | #include "cairo/cairo-features.h" |
107 | | #include "mozilla/WindowsDllBlocklist.h" |
108 | | #include "mozilla/WinHeaderOnlyUtils.h" |
109 | | #include "mozilla/mscom/MainThreadRuntime.h" |
110 | | #include "mozilla/widget/AudioSession.h" |
111 | | |
112 | | #ifndef PROCESS_DEP_ENABLE |
113 | | #define PROCESS_DEP_ENABLE 0x1 |
114 | | #endif |
115 | | #endif |
116 | | |
117 | | #if defined(MOZ_CONTENT_SANDBOX) |
118 | | #include "mozilla/SandboxSettings.h" |
119 | | #if (defined(XP_WIN) || defined(XP_MACOSX)) |
120 | | #include "nsIUUIDGenerator.h" |
121 | | #endif |
122 | | #endif |
123 | | |
124 | | #ifdef ACCESSIBILITY |
125 | | #include "nsAccessibilityService.h" |
126 | | #if defined(XP_WIN) |
127 | | #include "mozilla/a11y/Compatibility.h" |
128 | | #include "mozilla/a11y/Platform.h" |
129 | | #endif |
130 | | #endif |
131 | | |
132 | | #include "nsCRT.h" |
133 | | #include "nsCOMPtr.h" |
134 | | #include "nsDirectoryServiceDefs.h" |
135 | | #include "nsDirectoryServiceUtils.h" |
136 | | #include "nsEmbedCID.h" |
137 | | #include "nsNetUtil.h" |
138 | | #include "nsReadableUtils.h" |
139 | | #include "nsXPCOM.h" |
140 | | #include "nsXPCOMCIDInternal.h" |
141 | | #include "nsString.h" |
142 | | #include "nsPrintfCString.h" |
143 | | #include "nsVersionComparator.h" |
144 | | |
145 | | #include "nsAppDirectoryServiceDefs.h" |
146 | | #include "nsXULAppAPI.h" |
147 | | #include "nsXREDirProvider.h" |
148 | | #include "nsToolkitCompsCID.h" |
149 | | |
150 | | #include "nsINIParser.h" |
151 | | #include "mozilla/Omnijar.h" |
152 | | #include "mozilla/StartupTimeline.h" |
153 | | #include "mozilla/LateWriteChecks.h" |
154 | | |
155 | | #include <stdlib.h> |
156 | | #include <locale.h> |
157 | | |
158 | | #ifdef XP_UNIX |
159 | | #include <errno.h> |
160 | | #include <pwd.h> |
161 | | #include <string.h> |
162 | | #include <sys/resource.h> |
163 | | #include <sys/stat.h> |
164 | | #include <unistd.h> |
165 | | #endif |
166 | | |
167 | | #ifdef XP_WIN |
168 | | #include <process.h> |
169 | | #include <shlobj.h> |
170 | | #include "mozilla/WinDllServices.h" |
171 | | #include "nsThreadUtils.h" |
172 | | #include <comdef.h> |
173 | | #include <wbemidl.h> |
174 | | #include "WinUtils.h" |
175 | | #endif |
176 | | |
177 | | #ifdef XP_MACOSX |
178 | | #include "nsILocalFileMac.h" |
179 | | #include "nsCommandLineServiceMac.h" |
180 | | #endif |
181 | | |
182 | | // for X remote support |
183 | | #ifdef MOZ_ENABLE_XREMOTE |
184 | | #include "XRemoteClient.h" |
185 | | #include "nsIRemoteService.h" |
186 | | #include "nsProfileLock.h" |
187 | | #include "SpecialSystemDirectory.h" |
188 | | #include <sched.h> |
189 | | #ifdef MOZ_ENABLE_DBUS |
190 | | #include "DBusRemoteClient.h" |
191 | | #endif |
192 | | // Time to wait for the remoting service to start |
193 | 0 | #define MOZ_XREMOTE_START_TIMEOUT_SEC 5 |
194 | | #endif |
195 | | |
196 | | #if defined(DEBUG) && defined(XP_WIN32) |
197 | | #include <malloc.h> |
198 | | #endif |
199 | | |
200 | | #if defined (XP_MACOSX) |
201 | | #include <Carbon/Carbon.h> |
202 | | #endif |
203 | | |
204 | | #ifdef DEBUG |
205 | | #include "mozilla/Logging.h" |
206 | | #endif |
207 | | |
208 | | #ifdef MOZ_JPROF |
209 | | #include "jprof.h" |
210 | | #endif |
211 | | |
212 | | #include "nsExceptionHandler.h" |
213 | | #include "nsICrashReporter.h" |
214 | | #define NS_CRASHREPORTER_CONTRACTID "@mozilla.org/toolkit/crash-reporter;1" |
215 | | #include "nsIPrefService.h" |
216 | | #include "nsIMemoryInfoDumper.h" |
217 | | #if defined(XP_LINUX) && !defined(ANDROID) |
218 | | #include "mozilla/widget/LSBUtils.h" |
219 | | #endif |
220 | | |
221 | | #include "base/command_line.h" |
222 | | #include "GTestRunner.h" |
223 | | |
224 | | #ifdef MOZ_WIDGET_ANDROID |
225 | | #include "GeneratedJNIWrappers.h" |
226 | | #endif |
227 | | |
228 | | #if defined(MOZ_SANDBOX) |
229 | | #if defined(XP_LINUX) && !defined(ANDROID) |
230 | | #include "mozilla/SandboxInfo.h" |
231 | | #elif defined(XP_WIN) |
232 | | #include "sandboxBroker.h" |
233 | | #include "sandboxPermissions.h" |
234 | | #endif |
235 | | #endif |
236 | | |
237 | | #ifdef MOZ_CODE_COVERAGE |
238 | | #include "mozilla/CodeCoverageHandler.h" |
239 | | #endif |
240 | | |
241 | | #include "mozilla/mozalloc_oom.h" |
242 | | #include "SafeMode.h" |
243 | | |
244 | | extern uint32_t gRestartMode; |
245 | | extern void InstallSignalHandlers(const char *ProgramName); |
246 | | |
247 | 0 | #define FILE_COMPATIBILITY_INFO NS_LITERAL_CSTRING("compatibility.ini") |
248 | 0 | #define FILE_INVALIDATE_CACHES NS_LITERAL_CSTRING(".purgecaches") |
249 | | #define FILE_STARTUP_INCOMPLETE NS_LITERAL_STRING(".startup-incomplete") |
250 | | |
251 | | int gArgc; |
252 | | char **gArgv; |
253 | | |
254 | | #include "buildid.h" |
255 | | |
256 | | static const char gToolkitVersion[] = NS_STRINGIFY(GRE_MILESTONE); |
257 | | static const char gToolkitBuildID[] = NS_STRINGIFY(MOZ_BUILDID); |
258 | | |
259 | | static nsIProfileLock* gProfileLock; |
260 | | |
261 | | int gRestartArgc; |
262 | | char **gRestartArgv; |
263 | | |
264 | | // If gRestartedByOS is set, we were automatically restarted by the OS. |
265 | | bool gRestartedByOS = false; |
266 | | |
267 | | bool gIsGtest = false; |
268 | | |
269 | | nsString gAbsoluteArgv0Path; |
270 | | |
271 | | #if defined(MOZ_WIDGET_GTK) |
272 | | #include <glib.h> |
273 | | #if defined(DEBUG) || defined(NS_BUILD_REFCNT_LOGGING) |
274 | | #define CLEANUP_MEMORY 1 |
275 | | #define PANGO_ENABLE_BACKEND |
276 | | #include <pango/pangofc-fontmap.h> |
277 | | #endif |
278 | | #include <gtk/gtk.h> |
279 | | #ifdef MOZ_WAYLAND |
280 | | #include <gdk/gdkwayland.h> |
281 | | #endif |
282 | | #ifdef MOZ_X11 |
283 | | #include <gdk/gdkx.h> |
284 | | #endif /* MOZ_X11 */ |
285 | | #include "nsGTKToolkit.h" |
286 | | #include <fontconfig/fontconfig.h> |
287 | | #endif |
288 | | #include "BinaryPath.h" |
289 | | |
290 | | #ifdef MOZ_LINKER |
291 | | extern "C" MFBT_API bool IsSignalHandlingBroken(); |
292 | | #endif |
293 | | |
294 | | #ifdef FUZZING |
295 | | #include "FuzzerRunner.h" |
296 | | |
297 | | namespace mozilla { |
298 | | FuzzerRunner* fuzzerRunner = 0; |
299 | | } // namespace mozilla |
300 | | |
301 | | #ifdef LIBFUZZER |
302 | 3 | void XRE_LibFuzzerSetDriver(LibFuzzerDriver aDriver) { |
303 | 3 | mozilla::fuzzerRunner->setParams(aDriver); |
304 | 3 | } |
305 | | #endif |
306 | | #endif // FUZZING |
307 | | |
308 | | namespace mozilla { |
309 | | int (*RunGTest)(int*, char**) = 0; |
310 | | } // namespace mozilla |
311 | | |
312 | | using namespace mozilla; |
313 | | using namespace mozilla::startup; |
314 | | using mozilla::Unused; |
315 | | using mozilla::scache::StartupCache; |
316 | | using mozilla::dom::ContentParent; |
317 | | using mozilla::dom::ContentChild; |
318 | | using mozilla::intl::LocaleService; |
319 | | |
320 | | // Save the given word to the specified environment variable. |
321 | | static void |
322 | | SaveWordToEnv(const char *name, const nsACString & word) |
323 | 0 | { |
324 | 0 | char *expr = Smprintf("%s=%s", name, PromiseFlatCString(word).get()).release(); |
325 | 0 | if (expr) |
326 | 0 | PR_SetEnv(expr); |
327 | 0 | // We intentionally leak |expr| here since it is required by PR_SetEnv. |
328 | 0 | } |
329 | | |
330 | | // Save the path of the given file to the specified environment variable. |
331 | | static void |
332 | | SaveFileToEnv(const char *name, nsIFile *file) |
333 | 0 | { |
334 | | #ifdef XP_WIN |
335 | | nsAutoString path; |
336 | | file->GetPath(path); |
337 | | SetEnvironmentVariableW(NS_ConvertASCIItoUTF16(name).get(), path.get()); |
338 | | #else |
339 | | nsAutoCString path; |
340 | 0 | file->GetNativePath(path); |
341 | 0 | SaveWordToEnv(name, path); |
342 | 0 | #endif |
343 | 0 | } |
344 | | |
345 | | // Load the path of a file saved with SaveFileToEnv |
346 | | #ifndef MOZ_ASAN_REPORTER |
347 | | static |
348 | | #endif |
349 | | already_AddRefed<nsIFile> |
350 | | GetFileFromEnv(const char *name) |
351 | 0 | { |
352 | 0 | nsresult rv; |
353 | 0 | nsCOMPtr<nsIFile> file; |
354 | 0 |
|
355 | | #ifdef XP_WIN |
356 | | WCHAR path[_MAX_PATH]; |
357 | | if (!GetEnvironmentVariableW(NS_ConvertASCIItoUTF16(name).get(), |
358 | | path, _MAX_PATH)) |
359 | | return nullptr; |
360 | | |
361 | | rv = NS_NewLocalFile(nsDependentString(path), true, getter_AddRefs(file)); |
362 | | if (NS_FAILED(rv)) |
363 | | return nullptr; |
364 | | |
365 | | return file.forget(); |
366 | | #else |
367 | | const char *arg = PR_GetEnv(name); |
368 | 0 | if (!arg || !*arg) |
369 | 0 | return nullptr; |
370 | 0 | |
371 | 0 | rv = NS_NewNativeLocalFile(nsDependentCString(arg), true, |
372 | 0 | getter_AddRefs(file)); |
373 | 0 | if (NS_FAILED(rv)) |
374 | 0 | return nullptr; |
375 | 0 | |
376 | 0 | return file.forget(); |
377 | 0 | #endif |
378 | 0 | } |
379 | | |
380 | | // Save the path of the given word to the specified environment variable |
381 | | // provided the environment variable does not have a value. |
382 | | static void |
383 | | SaveWordToEnvIfUnset(const char *name, const nsACString & word) |
384 | 0 | { |
385 | 0 | if (!EnvHasValue(name)) |
386 | 0 | SaveWordToEnv(name, word); |
387 | 0 | } |
388 | | |
389 | | // Save the path of the given file to the specified environment variable |
390 | | // provided the environment variable does not have a value. |
391 | | static void |
392 | | SaveFileToEnvIfUnset(const char *name, nsIFile *file) |
393 | 0 | { |
394 | 0 | if (!EnvHasValue(name)) |
395 | 0 | SaveFileToEnv(name, file); |
396 | 0 | } |
397 | | |
398 | | static bool gIsExpectedExit = false; |
399 | | |
400 | 3 | void MozExpectedExit() { |
401 | 3 | gIsExpectedExit = true; |
402 | 3 | } |
403 | | |
404 | | /** |
405 | | * Runs atexit() to catch unexpected exit from 3rd party libraries like the |
406 | | * Intel graphics driver calling exit in an error condition. When they |
407 | | * call exit() to report an error we won't shutdown correctly and wont catch |
408 | | * the issue with our crash reporter. |
409 | | */ |
410 | 3 | static void UnexpectedExit() { |
411 | 3 | if (!gIsExpectedExit) { |
412 | 0 | gIsExpectedExit = true; // Don't risk re-entrency issues when crashing. |
413 | 0 | MOZ_CRASH("Exit called by third party code."); |
414 | 0 | } |
415 | 3 | } |
416 | | |
417 | | /** |
418 | | * Output a string to the user. This method is really only meant to be used to |
419 | | * output last-ditch error messages designed for developers NOT END USERS. |
420 | | * |
421 | | * @param isError |
422 | | * Pass true to indicate severe errors. |
423 | | * @param fmt |
424 | | * printf-style format string followed by arguments. |
425 | | */ |
426 | | static MOZ_FORMAT_PRINTF(2, 3) void Output(bool isError, const char *fmt, ... ) |
427 | 0 | { |
428 | 0 | va_list ap; |
429 | 0 | va_start(ap, fmt); |
430 | 0 |
|
431 | | #if defined(XP_WIN) && !MOZ_WINCONSOLE |
432 | | SmprintfPointer msg = mozilla::Vsmprintf(fmt, ap); |
433 | | if (msg) |
434 | | { |
435 | | UINT flags = MB_OK; |
436 | | if (isError) |
437 | | flags |= MB_ICONERROR; |
438 | | else |
439 | | flags |= MB_ICONINFORMATION; |
440 | | |
441 | | wchar_t wide_msg[1024]; |
442 | | MultiByteToWideChar(CP_ACP, |
443 | | 0, |
444 | | msg.get(), |
445 | | -1, |
446 | | wide_msg, |
447 | | sizeof(wide_msg) / sizeof(wchar_t)); |
448 | | |
449 | | MessageBoxW(nullptr, wide_msg, L"XULRunner", flags); |
450 | | } |
451 | | #else |
452 | | vfprintf(stderr, fmt, ap); |
453 | 0 | #endif |
454 | 0 |
|
455 | 0 | va_end(ap); |
456 | 0 | } |
457 | | |
458 | | enum RemoteResult { |
459 | | REMOTE_NOT_FOUND = 0, |
460 | | REMOTE_FOUND = 1, |
461 | | REMOTE_ARG_BAD = 2 |
462 | | }; |
463 | | |
464 | | /** |
465 | | * Check for a commandline flag. If the flag takes a parameter, the |
466 | | * parameter is returned in aParam. Flags may be in the form -arg or |
467 | | * --arg (or /arg on win32). |
468 | | * |
469 | | * @param aArg the parameter to check. Must be lowercase. |
470 | | * @param aParam if non-null, the -arg <data> will be stored in this pointer. |
471 | | * This is *not* allocated, but rather a pointer to the argv data. |
472 | | * @param aFlags flags @see CheckArgFlag |
473 | | */ |
474 | | static ArgResult |
475 | | CheckArg(const char* aArg, const char** aParam = nullptr, |
476 | | CheckArgFlag aFlags = CheckArgFlag::RemoveArg) |
477 | 39 | { |
478 | 39 | MOZ_ASSERT(gArgv, "gArgv must be initialized before CheckArg()"); |
479 | 39 | return CheckArg(gArgc, gArgv, aArg, aParam, aFlags); |
480 | 39 | } |
481 | | |
482 | | /** |
483 | | * Check for a commandline flag. Ignore data that's passed in with the flag. |
484 | | * Flags may be in the form -arg or --arg (or /arg on win32). |
485 | | * Will not remove flag if found. |
486 | | * |
487 | | * @param aArg the parameter to check. Must be lowercase. |
488 | | */ |
489 | | static ArgResult |
490 | | CheckArgExists(const char* aArg) |
491 | 3 | { |
492 | 3 | return CheckArg(aArg, nullptr, CheckArgFlag::None); |
493 | 3 | } |
494 | | |
495 | | #if defined(XP_WIN) |
496 | | /** |
497 | | * Check for a commandline flag from the windows shell and remove it from the |
498 | | * argv used when restarting. Flags MUST be in the form -arg. |
499 | | * |
500 | | * @param aArg the parameter to check. Must be lowercase. |
501 | | */ |
502 | | static ArgResult |
503 | | CheckArgShell(const char* aArg) |
504 | | { |
505 | | char **curarg = gRestartArgv + 1; // skip argv[0] |
506 | | |
507 | | while (*curarg) { |
508 | | char *arg = curarg[0]; |
509 | | |
510 | | if (arg[0] == '-') { |
511 | | ++arg; |
512 | | |
513 | | if (strimatch(aArg, arg)) { |
514 | | do { |
515 | | *curarg = *(curarg + 1); |
516 | | ++curarg; |
517 | | } while (*curarg); |
518 | | |
519 | | --gRestartArgc; |
520 | | |
521 | | return ARG_FOUND; |
522 | | } |
523 | | } |
524 | | |
525 | | ++curarg; |
526 | | } |
527 | | |
528 | | return ARG_NONE; |
529 | | } |
530 | | |
531 | | /** |
532 | | * Enabled Native App Support to process DDE messages when the app needs to |
533 | | * restart and the app has been launched by the Windows shell to open an url. |
534 | | * When aWait is false this will process the DDE events manually. This prevents |
535 | | * Windows from displaying an error message due to the DDE message not being |
536 | | * acknowledged. |
537 | | */ |
538 | | static void |
539 | | ProcessDDE(nsINativeAppSupport* aNative, bool aWait) |
540 | | { |
541 | | // When the app is launched by the windows shell the windows shell |
542 | | // expects the app to be available for DDE messages and if it isn't |
543 | | // windows displays an error dialog. To prevent the error the DDE server |
544 | | // is enabled and pending events are processed when the app needs to |
545 | | // restart after it was launched by the shell with the requestpending |
546 | | // argument. The requestpending pending argument is removed to |
547 | | // differentiate it from being launched when an app restart is not |
548 | | // required. |
549 | | ArgResult ar; |
550 | | ar = CheckArgShell("requestpending"); |
551 | | if (ar == ARG_FOUND) { |
552 | | aNative->Enable(); // enable win32 DDE responses |
553 | | if (aWait) { |
554 | | // This is just a guesstimate based on testing different values. |
555 | | // If count is 8 or less windows will display an error dialog. |
556 | | int32_t count = 20; |
557 | | SpinEventLoopUntil([&]() { return --count < 0; }); |
558 | | } |
559 | | } |
560 | | } |
561 | | #endif |
562 | | |
563 | | bool gSafeMode = false; |
564 | | |
565 | | /** |
566 | | * The nsXULAppInfo object implements nsIFactory so that it can be its own |
567 | | * singleton. |
568 | | */ |
569 | | class nsXULAppInfo : public nsIXULAppInfo, |
570 | | public nsIObserver, |
571 | | #ifdef XP_WIN |
572 | | public nsIWinAppHelper, |
573 | | #endif |
574 | | public nsICrashReporter, |
575 | | public nsIFinishDumpingCallback, |
576 | | public nsIXULRuntime |
577 | | |
578 | | { |
579 | | public: |
580 | 0 | constexpr nsXULAppInfo() {} |
581 | | NS_DECL_ISUPPORTS_INHERITED |
582 | | NS_DECL_NSIPLATFORMINFO |
583 | | NS_DECL_NSIXULAPPINFO |
584 | | NS_DECL_NSIXULRUNTIME |
585 | | NS_DECL_NSIOBSERVER |
586 | | NS_DECL_NSICRASHREPORTER |
587 | | NS_DECL_NSIFINISHDUMPINGCALLBACK |
588 | | #ifdef XP_WIN |
589 | | NS_DECL_NSIWINAPPHELPER |
590 | | #endif |
591 | | }; |
592 | | |
593 | 41 | NS_INTERFACE_MAP_BEGIN(nsXULAppInfo) |
594 | 41 | NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXULRuntime) |
595 | 41 | NS_INTERFACE_MAP_ENTRY(nsIXULRuntime) |
596 | 41 | NS_INTERFACE_MAP_ENTRY(nsIObserver) |
597 | | #ifdef XP_WIN |
598 | | NS_INTERFACE_MAP_ENTRY(nsIWinAppHelper) |
599 | | #endif |
600 | 19 | NS_INTERFACE_MAP_ENTRY(nsICrashReporter) |
601 | 19 | NS_INTERFACE_MAP_ENTRY(nsIFinishDumpingCallback) |
602 | 19 | NS_INTERFACE_MAP_ENTRY(nsIPlatformInfo) |
603 | 19 | NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIXULAppInfo, gAppData || |
604 | 14 | XRE_IsContentProcess()) |
605 | 14 | NS_INTERFACE_MAP_END |
606 | | |
607 | | NS_IMETHODIMP_(MozExternalRefCountType) |
608 | | nsXULAppInfo::AddRef() |
609 | 44 | { |
610 | 44 | return 1; |
611 | 44 | } |
612 | | |
613 | | NS_IMETHODIMP_(MozExternalRefCountType) |
614 | | nsXULAppInfo::Release() |
615 | 41 | { |
616 | 41 | return 1; |
617 | 41 | } |
618 | | |
619 | | NS_IMETHODIMP |
620 | | nsXULAppInfo::GetVendor(nsACString& aResult) |
621 | 0 | { |
622 | 0 | if (XRE_IsContentProcess()) { |
623 | 0 | ContentChild* cc = ContentChild::GetSingleton(); |
624 | 0 | aResult = cc->GetAppInfo().vendor; |
625 | 0 | return NS_OK; |
626 | 0 | } |
627 | 0 | aResult.Assign(gAppData->vendor); |
628 | 0 |
|
629 | 0 | return NS_OK; |
630 | 0 | } |
631 | | |
632 | | NS_IMETHODIMP |
633 | | nsXULAppInfo::GetName(nsACString& aResult) |
634 | 1 | { |
635 | 1 | if (XRE_IsContentProcess()) { |
636 | 0 | ContentChild* cc = ContentChild::GetSingleton(); |
637 | 0 | aResult = cc->GetAppInfo().name; |
638 | 0 | return NS_OK; |
639 | 0 | } |
640 | 1 | aResult.Assign(gAppData->name); |
641 | 1 | |
642 | 1 | return NS_OK; |
643 | 1 | } |
644 | | |
645 | | NS_IMETHODIMP |
646 | | nsXULAppInfo::GetID(nsACString& aResult) |
647 | 12 | { |
648 | 12 | if (XRE_IsContentProcess()) { |
649 | 0 | ContentChild* cc = ContentChild::GetSingleton(); |
650 | 0 | aResult = cc->GetAppInfo().ID; |
651 | 0 | return NS_OK; |
652 | 0 | } |
653 | 12 | aResult.Assign(gAppData->ID); |
654 | 12 | |
655 | 12 | return NS_OK; |
656 | 12 | } |
657 | | |
658 | | NS_IMETHODIMP |
659 | | nsXULAppInfo::GetVersion(nsACString& aResult) |
660 | 14 | { |
661 | 14 | if (XRE_IsContentProcess()) { |
662 | 0 | ContentChild* cc = ContentChild::GetSingleton(); |
663 | 0 | aResult = cc->GetAppInfo().version; |
664 | 0 | return NS_OK; |
665 | 0 | } |
666 | 14 | aResult.Assign(gAppData->version); |
667 | 14 | |
668 | 14 | return NS_OK; |
669 | 14 | } |
670 | | |
671 | | NS_IMETHODIMP |
672 | | nsXULAppInfo::GetPlatformVersion(nsACString& aResult) |
673 | 12 | { |
674 | 12 | aResult.Assign(gToolkitVersion); |
675 | 12 | |
676 | 12 | return NS_OK; |
677 | 12 | } |
678 | | |
679 | | NS_IMETHODIMP |
680 | | nsXULAppInfo::GetAppBuildID(nsACString& aResult) |
681 | 0 | { |
682 | 0 | if (XRE_IsContentProcess()) { |
683 | 0 | ContentChild* cc = ContentChild::GetSingleton(); |
684 | 0 | aResult = cc->GetAppInfo().buildID; |
685 | 0 | return NS_OK; |
686 | 0 | } |
687 | 0 | aResult.Assign(gAppData->buildID); |
688 | 0 |
|
689 | 0 | return NS_OK; |
690 | 0 | } |
691 | | |
692 | | NS_IMETHODIMP |
693 | | nsXULAppInfo::GetPlatformBuildID(nsACString& aResult) |
694 | 5 | { |
695 | 5 | aResult.Assign(gToolkitBuildID); |
696 | 5 | |
697 | 5 | return NS_OK; |
698 | 5 | } |
699 | | |
700 | | NS_IMETHODIMP |
701 | | nsXULAppInfo::GetUAName(nsACString& aResult) |
702 | 1 | { |
703 | 1 | if (XRE_IsContentProcess()) { |
704 | 0 | ContentChild* cc = ContentChild::GetSingleton(); |
705 | 0 | aResult = cc->GetAppInfo().UAName; |
706 | 0 | return NS_OK; |
707 | 0 | } |
708 | 1 | aResult.Assign(gAppData->UAName); |
709 | 1 | |
710 | 1 | return NS_OK; |
711 | 1 | } |
712 | | |
713 | | NS_IMETHODIMP |
714 | | nsXULAppInfo::GetSourceURL(nsACString& aResult) |
715 | 0 | { |
716 | 0 | if (XRE_IsContentProcess()) { |
717 | 0 | ContentChild* cc = ContentChild::GetSingleton(); |
718 | 0 | aResult = cc->GetAppInfo().sourceURL; |
719 | 0 | return NS_OK; |
720 | 0 | } |
721 | 0 | aResult.Assign(gAppData->sourceURL); |
722 | 0 |
|
723 | 0 | return NS_OK; |
724 | 0 | } |
725 | | |
726 | | NS_IMETHODIMP |
727 | | nsXULAppInfo::GetLogConsoleErrors(bool *aResult) |
728 | 0 | { |
729 | 0 | *aResult = gLogConsoleErrors; |
730 | 0 | return NS_OK; |
731 | 0 | } |
732 | | |
733 | | NS_IMETHODIMP |
734 | | nsXULAppInfo::SetLogConsoleErrors(bool aValue) |
735 | 0 | { |
736 | 0 | gLogConsoleErrors = aValue; |
737 | 0 | return NS_OK; |
738 | 0 | } |
739 | | |
740 | | NS_IMETHODIMP |
741 | | nsXULAppInfo::GetInSafeMode(bool *aResult) |
742 | 6 | { |
743 | 6 | *aResult = gSafeMode; |
744 | 6 | return NS_OK; |
745 | 6 | } |
746 | | |
747 | | NS_IMETHODIMP |
748 | | nsXULAppInfo::GetOS(nsACString& aResult) |
749 | 12 | { |
750 | 12 | aResult.AssignLiteral(OS_TARGET); |
751 | 12 | return NS_OK; |
752 | 12 | } |
753 | | |
754 | | NS_IMETHODIMP |
755 | | nsXULAppInfo::GetXPCOMABI(nsACString& aResult) |
756 | 12 | { |
757 | 12 | #ifdef TARGET_XPCOM_ABI |
758 | 12 | aResult.AssignLiteral(TARGET_XPCOM_ABI); |
759 | 12 | return NS_OK; |
760 | | #else |
761 | | return NS_ERROR_NOT_AVAILABLE; |
762 | | #endif |
763 | | } |
764 | | |
765 | | NS_IMETHODIMP |
766 | | nsXULAppInfo::GetWidgetToolkit(nsACString& aResult) |
767 | 0 | { |
768 | 0 | aResult.AssignLiteral(MOZ_WIDGET_TOOLKIT); |
769 | 0 | return NS_OK; |
770 | 0 | } |
771 | | |
772 | | // Ensure that the GeckoProcessType enum, defined in xpcom/build/nsXULAppAPI.h, |
773 | | // is synchronized with the const unsigned longs defined in |
774 | | // xpcom/system/nsIXULRuntime.idl. |
775 | | #define SYNC_ENUMS(a,b) \ |
776 | | static_assert(nsIXULRuntime::PROCESS_TYPE_ ## a == \ |
777 | | static_cast<int>(GeckoProcessType_ ## b), \ |
778 | | "GeckoProcessType in nsXULAppAPI.h not synchronized with nsIXULRuntime.idl"); |
779 | | |
780 | | SYNC_ENUMS(DEFAULT, Default) |
781 | | SYNC_ENUMS(PLUGIN, Plugin) |
782 | | SYNC_ENUMS(CONTENT, Content) |
783 | | SYNC_ENUMS(IPDLUNITTEST, IPDLUnitTest) |
784 | | SYNC_ENUMS(GMPLUGIN, GMPlugin) |
785 | | SYNC_ENUMS(GPU, GPU) |
786 | | SYNC_ENUMS(PDFIUM, PDFium) |
787 | | SYNC_ENUMS(VR, VR) |
788 | | |
789 | | // .. and ensure that that is all of them: |
790 | | static_assert(GeckoProcessType_VR + 1 == GeckoProcessType_End, |
791 | | "Did not find the final GeckoProcessType"); |
792 | | |
793 | | NS_IMETHODIMP |
794 | | nsXULAppInfo::GetProcessType(uint32_t* aResult) |
795 | 0 | { |
796 | 0 | NS_ENSURE_ARG_POINTER(aResult); |
797 | 0 | *aResult = XRE_GetProcessType(); |
798 | 0 | return NS_OK; |
799 | 0 | } |
800 | | |
801 | | NS_IMETHODIMP |
802 | | nsXULAppInfo::GetProcessID(uint32_t* aResult) |
803 | 4 | { |
804 | | #ifdef XP_WIN |
805 | | *aResult = GetCurrentProcessId(); |
806 | | #else |
807 | | *aResult = getpid(); |
808 | 4 | #endif |
809 | 4 | return NS_OK; |
810 | 4 | } |
811 | | |
812 | | NS_IMETHODIMP |
813 | | nsXULAppInfo::GetUniqueProcessID(uint64_t* aResult) |
814 | 0 | { |
815 | 0 | if (XRE_IsContentProcess()) { |
816 | 0 | ContentChild* cc = ContentChild::GetSingleton(); |
817 | 0 | *aResult = cc->GetID(); |
818 | 0 | } else { |
819 | 0 | *aResult = 0; |
820 | 0 | } |
821 | 0 | return NS_OK; |
822 | 0 | } |
823 | | |
824 | | NS_IMETHODIMP |
825 | | nsXULAppInfo::GetRemoteType(nsAString& aRemoteType) |
826 | 0 | { |
827 | 0 | if (XRE_IsContentProcess()) { |
828 | 0 | ContentChild* cc = ContentChild::GetSingleton(); |
829 | 0 | aRemoteType.Assign(cc->GetRemoteType()); |
830 | 0 | } else { |
831 | 0 | SetDOMStringToNull(aRemoteType); |
832 | 0 | } |
833 | 0 |
|
834 | 0 | return NS_OK; |
835 | 0 | } |
836 | | |
837 | | static bool gBrowserTabsRemoteAutostart = false; |
838 | | static uint64_t gBrowserTabsRemoteStatus = 0; |
839 | | static bool gBrowserTabsRemoteAutostartInitialized = false; |
840 | | |
841 | | NS_IMETHODIMP |
842 | 0 | nsXULAppInfo::Observe(nsISupports *aSubject, const char *aTopic, const char16_t *aData) { |
843 | 0 | if (!nsCRT::strcmp(aTopic, "getE10SBlocked")) { |
844 | 0 | nsCOMPtr<nsISupportsPRUint64> ret = do_QueryInterface(aSubject); |
845 | 0 | if (!ret) |
846 | 0 | return NS_ERROR_FAILURE; |
847 | 0 | |
848 | 0 | ret->SetData(gBrowserTabsRemoteStatus); |
849 | 0 |
|
850 | 0 | return NS_OK; |
851 | 0 | } |
852 | 0 | return NS_ERROR_FAILURE; |
853 | 0 | } |
854 | | |
855 | | NS_IMETHODIMP |
856 | | nsXULAppInfo::GetBrowserTabsRemoteAutostart(bool* aResult) |
857 | 0 | { |
858 | 0 | *aResult = BrowserTabsRemoteAutostart(); |
859 | 0 | return NS_OK; |
860 | 0 | } |
861 | | |
862 | | NS_IMETHODIMP |
863 | | nsXULAppInfo::GetMaxWebProcessCount(uint32_t* aResult) |
864 | 0 | { |
865 | 0 | *aResult = mozilla::GetMaxWebProcessCount(); |
866 | 0 | return NS_OK; |
867 | 0 | } |
868 | | |
869 | | NS_IMETHODIMP |
870 | | nsXULAppInfo::GetAccessibilityEnabled(bool* aResult) |
871 | 0 | { |
872 | 0 | #ifdef ACCESSIBILITY |
873 | 0 | *aResult = GetAccService() != nullptr; |
874 | | #else |
875 | | *aResult = false; |
876 | | #endif |
877 | | return NS_OK; |
878 | 0 | } |
879 | | |
880 | | NS_IMETHODIMP |
881 | | nsXULAppInfo::GetAccessibleHandlerUsed(bool* aResult) |
882 | 0 | { |
883 | | #if defined(ACCESSIBILITY) && defined(XP_WIN) |
884 | | *aResult = Preferences::GetBool("accessibility.handler.enabled", false) && |
885 | | a11y::IsHandlerRegistered(); |
886 | | #else |
887 | | *aResult = false; |
888 | 0 | #endif |
889 | 0 | return NS_OK; |
890 | 0 | } |
891 | | |
892 | | NS_IMETHODIMP |
893 | | nsXULAppInfo::GetAccessibilityInstantiator(nsAString &aInstantiator) |
894 | 0 | { |
895 | | #if defined(ACCESSIBILITY) && defined(XP_WIN) |
896 | | if (!GetAccService()) { |
897 | | aInstantiator = NS_LITERAL_STRING(""); |
898 | | return NS_OK; |
899 | | } |
900 | | nsAutoString ipClientInfo; |
901 | | a11y::Compatibility::GetHumanReadableConsumersStr(ipClientInfo); |
902 | | aInstantiator.Append(ipClientInfo); |
903 | | aInstantiator.AppendLiteral("|"); |
904 | | |
905 | | nsCOMPtr<nsIFile> oopClientExe; |
906 | | if (a11y::GetInstantiator(getter_AddRefs(oopClientExe))) { |
907 | | nsAutoString oopClientInfo; |
908 | | if (NS_SUCCEEDED(oopClientExe->GetPath(oopClientInfo))) { |
909 | | aInstantiator.Append(oopClientInfo); |
910 | | } |
911 | | } |
912 | | #else |
913 | 0 | aInstantiator = NS_LITERAL_STRING(""); |
914 | 0 | #endif |
915 | 0 | return NS_OK; |
916 | 0 | } |
917 | | |
918 | | NS_IMETHODIMP |
919 | | nsXULAppInfo::GetShouldBlockIncompatJaws(bool* aResult) |
920 | 0 | { |
921 | 0 | *aResult = false; |
922 | | #if defined(ACCESSIBILITY) && defined(XP_WIN) |
923 | | *aResult = mozilla::a11y::Compatibility::IsOldJAWS(); |
924 | | #endif |
925 | | return NS_OK; |
926 | 0 | } |
927 | | |
928 | | NS_IMETHODIMP |
929 | | nsXULAppInfo::GetIs64Bit(bool* aResult) |
930 | 0 | { |
931 | 0 | #ifdef HAVE_64BIT_BUILD |
932 | 0 | *aResult = true; |
933 | | #else |
934 | | *aResult = false; |
935 | | #endif |
936 | | return NS_OK; |
937 | 0 | } |
938 | | |
939 | | NS_IMETHODIMP |
940 | | nsXULAppInfo::EnsureContentProcess() |
941 | 0 | { |
942 | 0 | if (!XRE_IsParentProcess()) |
943 | 0 | return NS_ERROR_NOT_AVAILABLE; |
944 | 0 | |
945 | 0 | RefPtr<ContentParent> unused = ContentParent::GetNewOrUsedBrowserProcess( |
946 | 0 | nullptr, NS_LITERAL_STRING(DEFAULT_REMOTE_TYPE)); |
947 | 0 | return NS_OK; |
948 | 0 | } |
949 | | |
950 | | NS_IMETHODIMP |
951 | | nsXULAppInfo::InvalidateCachesOnRestart() |
952 | 0 | { |
953 | 0 | nsCOMPtr<nsIFile> file; |
954 | 0 | nsresult rv = NS_GetSpecialDirectory(NS_APP_PROFILE_DIR_STARTUP, |
955 | 0 | getter_AddRefs(file)); |
956 | 0 | if (NS_FAILED(rv)) |
957 | 0 | return rv; |
958 | 0 | if (!file) |
959 | 0 | return NS_ERROR_NOT_AVAILABLE; |
960 | 0 | |
961 | 0 | file->AppendNative(FILE_COMPATIBILITY_INFO); |
962 | 0 |
|
963 | 0 | nsINIParser parser; |
964 | 0 | rv = parser.Init(file); |
965 | 0 | if (NS_FAILED(rv)) { |
966 | 0 | // This fails if compatibility.ini is not there, so we'll |
967 | 0 | // flush the caches on the next restart anyways. |
968 | 0 | return NS_OK; |
969 | 0 | } |
970 | 0 | |
971 | 0 | nsAutoCString buf; |
972 | 0 | rv = parser.GetString("Compatibility", "InvalidateCaches", buf); |
973 | 0 |
|
974 | 0 | if (NS_FAILED(rv)) { |
975 | 0 | PRFileDesc *fd; |
976 | 0 | rv = file->OpenNSPRFileDesc(PR_RDWR | PR_APPEND, 0600, &fd); |
977 | 0 | if (NS_FAILED(rv)) { |
978 | 0 | NS_ERROR("could not create output stream"); |
979 | 0 | return NS_ERROR_NOT_AVAILABLE; |
980 | 0 | } |
981 | 0 | static const char kInvalidationHeader[] = NS_LINEBREAK "InvalidateCaches=1" NS_LINEBREAK; |
982 | 0 | PR_Write(fd, kInvalidationHeader, sizeof(kInvalidationHeader) - 1); |
983 | 0 | PR_Close(fd); |
984 | 0 | } |
985 | 0 | return NS_OK; |
986 | 0 | } |
987 | | |
988 | | NS_IMETHODIMP |
989 | | nsXULAppInfo::GetReplacedLockTime(PRTime *aReplacedLockTime) |
990 | 0 | { |
991 | 0 | if (!gProfileLock) |
992 | 0 | return NS_ERROR_NOT_AVAILABLE; |
993 | 0 | gProfileLock->GetReplacedLockTime(aReplacedLockTime); |
994 | 0 | return NS_OK; |
995 | 0 | } |
996 | | |
997 | | NS_IMETHODIMP |
998 | | nsXULAppInfo::GetIsReleaseOrBeta(bool* aResult) |
999 | 0 | { |
1000 | | #ifdef RELEASE_OR_BETA |
1001 | | *aResult = true; |
1002 | | #else |
1003 | | *aResult = false; |
1004 | 0 | #endif |
1005 | 0 | return NS_OK; |
1006 | 0 | } |
1007 | | |
1008 | | NS_IMETHODIMP |
1009 | | nsXULAppInfo::GetIsOfficialBranding(bool* aResult) |
1010 | 0 | { |
1011 | | #ifdef MOZ_OFFICIAL_BRANDING |
1012 | | *aResult = true; |
1013 | | #else |
1014 | | *aResult = false; |
1015 | 0 | #endif |
1016 | 0 | return NS_OK; |
1017 | 0 | } |
1018 | | |
1019 | | NS_IMETHODIMP |
1020 | | nsXULAppInfo::GetDefaultUpdateChannel(nsACString& aResult) |
1021 | 0 | { |
1022 | 0 | aResult.AssignLiteral(NS_STRINGIFY(MOZ_UPDATE_CHANNEL)); |
1023 | 0 | return NS_OK; |
1024 | 0 | } |
1025 | | |
1026 | | NS_IMETHODIMP |
1027 | | nsXULAppInfo::GetDistributionID(nsACString& aResult) |
1028 | 0 | { |
1029 | 0 | aResult.AssignLiteral(MOZ_DISTRIBUTION_ID); |
1030 | 0 | return NS_OK; |
1031 | 0 | } |
1032 | | |
1033 | | NS_IMETHODIMP |
1034 | | nsXULAppInfo::GetWindowsDLLBlocklistStatus(bool* aResult) |
1035 | 0 | { |
1036 | | #if defined(HAS_DLL_BLOCKLIST) |
1037 | | *aResult = DllBlocklist_CheckStatus(); |
1038 | | #else |
1039 | | *aResult = false; |
1040 | 0 | #endif |
1041 | 0 | return NS_OK; |
1042 | 0 | } |
1043 | | |
1044 | | NS_IMETHODIMP |
1045 | | nsXULAppInfo::GetRestartedByOS(bool* aResult) |
1046 | 0 | { |
1047 | 0 | *aResult = gRestartedByOS; |
1048 | 0 | return NS_OK; |
1049 | 0 | } |
1050 | | |
1051 | | #ifdef XP_WIN |
1052 | | // Matches the enum in WinNT.h for the Vista SDK but renamed so that we can |
1053 | | // safely build with the Vista SDK and without it. |
1054 | | typedef enum |
1055 | | { |
1056 | | VistaTokenElevationTypeDefault = 1, |
1057 | | VistaTokenElevationTypeFull, |
1058 | | VistaTokenElevationTypeLimited |
1059 | | } VISTA_TOKEN_ELEVATION_TYPE; |
1060 | | |
1061 | | // avoid collision with TokeElevationType enum in WinNT.h |
1062 | | // of the Vista SDK |
1063 | | #define VistaTokenElevationType static_cast< TOKEN_INFORMATION_CLASS >( 18 ) |
1064 | | |
1065 | | NS_IMETHODIMP |
1066 | | nsXULAppInfo::GetUserCanElevate(bool *aUserCanElevate) |
1067 | | { |
1068 | | HANDLE hToken; |
1069 | | |
1070 | | VISTA_TOKEN_ELEVATION_TYPE elevationType; |
1071 | | DWORD dwSize; |
1072 | | |
1073 | | if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken) || |
1074 | | !GetTokenInformation(hToken, VistaTokenElevationType, &elevationType, |
1075 | | sizeof(elevationType), &dwSize)) { |
1076 | | *aUserCanElevate = false; |
1077 | | } |
1078 | | else { |
1079 | | // The possible values returned for elevationType and their meanings are: |
1080 | | // TokenElevationTypeDefault: The token does not have a linked token |
1081 | | // (e.g. UAC disabled or a standard user, so they can't be elevated) |
1082 | | // TokenElevationTypeFull: The token is linked to an elevated token |
1083 | | // (e.g. UAC is enabled and the user is already elevated so they can't |
1084 | | // be elevated again) |
1085 | | // TokenElevationTypeLimited: The token is linked to a limited token |
1086 | | // (e.g. UAC is enabled and the user is not elevated, so they can be |
1087 | | // elevated) |
1088 | | *aUserCanElevate = (elevationType == VistaTokenElevationTypeLimited); |
1089 | | } |
1090 | | |
1091 | | if (hToken) |
1092 | | CloseHandle(hToken); |
1093 | | |
1094 | | return NS_OK; |
1095 | | } |
1096 | | #endif |
1097 | | |
1098 | | NS_IMETHODIMP |
1099 | | nsXULAppInfo::GetEnabled(bool *aEnabled) |
1100 | 0 | { |
1101 | 0 | *aEnabled = CrashReporter::GetEnabled(); |
1102 | 0 | return NS_OK; |
1103 | 0 | } |
1104 | | |
1105 | | NS_IMETHODIMP |
1106 | | nsXULAppInfo::SetEnabled(bool aEnabled) |
1107 | 0 | { |
1108 | 0 | if (aEnabled) { |
1109 | 0 | if (CrashReporter::GetEnabled()) { |
1110 | 0 | // no point in erroring for double-enabling |
1111 | 0 | return NS_OK; |
1112 | 0 | } |
1113 | 0 | |
1114 | 0 | nsCOMPtr<nsIFile> greBinDir; |
1115 | 0 | NS_GetSpecialDirectory(NS_GRE_BIN_DIR, getter_AddRefs(greBinDir)); |
1116 | 0 | if (!greBinDir) { |
1117 | 0 | return NS_ERROR_FAILURE; |
1118 | 0 | } |
1119 | 0 | |
1120 | 0 | nsCOMPtr<nsIFile> xreBinDirectory = do_QueryInterface(greBinDir); |
1121 | 0 | if (!xreBinDirectory) { |
1122 | 0 | return NS_ERROR_FAILURE; |
1123 | 0 | } |
1124 | 0 | |
1125 | 0 | return CrashReporter::SetExceptionHandler(xreBinDirectory, true); |
1126 | 0 | } |
1127 | 0 | |
1128 | 0 | if (!CrashReporter::GetEnabled()) { |
1129 | 0 | // no point in erroring for double-disabling |
1130 | 0 | return NS_OK; |
1131 | 0 | } |
1132 | 0 | |
1133 | 0 | return CrashReporter::UnsetExceptionHandler(); |
1134 | 0 | } |
1135 | | |
1136 | | NS_IMETHODIMP |
1137 | | nsXULAppInfo::GetServerURL(nsIURL** aServerURL) |
1138 | 0 | { |
1139 | 0 | NS_ENSURE_ARG_POINTER(aServerURL); |
1140 | 0 | if (!CrashReporter::GetEnabled()) |
1141 | 0 | return NS_ERROR_NOT_INITIALIZED; |
1142 | 0 | |
1143 | 0 | nsAutoCString data; |
1144 | 0 | if (!CrashReporter::GetServerURL(data)) { |
1145 | 0 | return NS_ERROR_FAILURE; |
1146 | 0 | } |
1147 | 0 | nsCOMPtr<nsIURI> uri; |
1148 | 0 | NS_NewURI(getter_AddRefs(uri), data); |
1149 | 0 | if (!uri) |
1150 | 0 | return NS_ERROR_FAILURE; |
1151 | 0 | |
1152 | 0 | nsCOMPtr<nsIURL> url; |
1153 | 0 | url = do_QueryInterface(uri); |
1154 | 0 | NS_ADDREF(*aServerURL = url); |
1155 | 0 |
|
1156 | 0 | return NS_OK; |
1157 | 0 | } |
1158 | | |
1159 | | NS_IMETHODIMP |
1160 | | nsXULAppInfo::SetServerURL(nsIURL* aServerURL) |
1161 | 0 | { |
1162 | 0 | bool schemeOk; |
1163 | 0 | // only allow https or http URLs |
1164 | 0 | nsresult rv = aServerURL->SchemeIs("https", &schemeOk); |
1165 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
1166 | 0 | if (!schemeOk) { |
1167 | 0 | rv = aServerURL->SchemeIs("http", &schemeOk); |
1168 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
1169 | 0 |
|
1170 | 0 | if (!schemeOk) |
1171 | 0 | return NS_ERROR_INVALID_ARG; |
1172 | 0 | } |
1173 | 0 | nsAutoCString spec; |
1174 | 0 | rv = aServerURL->GetSpec(spec); |
1175 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
1176 | 0 |
|
1177 | 0 | return CrashReporter::SetServerURL(spec); |
1178 | 0 | } |
1179 | | |
1180 | | NS_IMETHODIMP |
1181 | | nsXULAppInfo::GetMinidumpPath(nsIFile** aMinidumpPath) |
1182 | 0 | { |
1183 | 0 | if (!CrashReporter::GetEnabled()) |
1184 | 0 | return NS_ERROR_NOT_INITIALIZED; |
1185 | 0 | |
1186 | 0 | nsAutoString path; |
1187 | 0 | if (!CrashReporter::GetMinidumpPath(path)) |
1188 | 0 | return NS_ERROR_FAILURE; |
1189 | 0 | |
1190 | 0 | nsresult rv = NS_NewLocalFile(path, false, aMinidumpPath); |
1191 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
1192 | 0 | return NS_OK; |
1193 | 0 | } |
1194 | | |
1195 | | NS_IMETHODIMP |
1196 | | nsXULAppInfo::SetMinidumpPath(nsIFile* aMinidumpPath) |
1197 | 0 | { |
1198 | 0 | nsAutoString path; |
1199 | 0 | nsresult rv = aMinidumpPath->GetPath(path); |
1200 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
1201 | 0 | return CrashReporter::SetMinidumpPath(path); |
1202 | 0 | } |
1203 | | |
1204 | | NS_IMETHODIMP |
1205 | | nsXULAppInfo::GetMinidumpForID(const nsAString& aId, nsIFile** aMinidump) |
1206 | 0 | { |
1207 | 0 | if (!CrashReporter::GetMinidumpForID(aId, aMinidump)) { |
1208 | 0 | return NS_ERROR_FILE_NOT_FOUND; |
1209 | 0 | } |
1210 | 0 | |
1211 | 0 | return NS_OK; |
1212 | 0 | } |
1213 | | |
1214 | | NS_IMETHODIMP |
1215 | | nsXULAppInfo::GetExtraFileForID(const nsAString& aId, nsIFile** aExtraFile) |
1216 | 0 | { |
1217 | 0 | if (!CrashReporter::GetExtraFileForID(aId, aExtraFile)) { |
1218 | 0 | return NS_ERROR_FILE_NOT_FOUND; |
1219 | 0 | } |
1220 | 0 | |
1221 | 0 | return NS_OK; |
1222 | 0 | } |
1223 | | |
1224 | | NS_IMETHODIMP |
1225 | | nsXULAppInfo::AnnotateCrashReport(const nsACString& key, |
1226 | | const nsACString& data) |
1227 | 0 | { |
1228 | 0 | CrashReporter::Annotation annotation; |
1229 | 0 |
|
1230 | 0 | if (!AnnotationFromString(annotation, PromiseFlatCString(key).get())) { |
1231 | 0 | return NS_ERROR_INVALID_ARG; |
1232 | 0 | } |
1233 | 0 | |
1234 | 0 | return CrashReporter::AnnotateCrashReport(annotation, data); |
1235 | 0 | } |
1236 | | |
1237 | | NS_IMETHODIMP |
1238 | | nsXULAppInfo::RemoveCrashReportAnnotation(const nsACString& key) |
1239 | 0 | { |
1240 | 0 | CrashReporter::Annotation annotation; |
1241 | 0 |
|
1242 | 0 | if (!AnnotationFromString(annotation, PromiseFlatCString(key).get())) { |
1243 | 0 | return NS_ERROR_INVALID_ARG; |
1244 | 0 | } |
1245 | 0 | |
1246 | 0 | return CrashReporter::RemoveCrashReportAnnotation(annotation); |
1247 | 0 | } |
1248 | | |
1249 | | NS_IMETHODIMP |
1250 | | nsXULAppInfo::IsAnnotationWhitelistedForPing(const nsACString& aValue, |
1251 | | bool* aIsWhitelisted) |
1252 | 0 | { |
1253 | 0 | CrashReporter::Annotation annotation; |
1254 | 0 |
|
1255 | 0 | if (!AnnotationFromString(annotation, PromiseFlatCString(aValue).get())) { |
1256 | 0 | return NS_ERROR_INVALID_ARG; |
1257 | 0 | } |
1258 | 0 | |
1259 | 0 | *aIsWhitelisted = CrashReporter::IsAnnotationWhitelistedForPing(annotation); |
1260 | 0 |
|
1261 | 0 | return NS_OK; |
1262 | 0 | } |
1263 | | |
1264 | | NS_IMETHODIMP |
1265 | | nsXULAppInfo::AppendAppNotesToCrashReport(const nsACString& data) |
1266 | 0 | { |
1267 | 0 | return CrashReporter::AppendAppNotesToCrashReport(data); |
1268 | 0 | } |
1269 | | |
1270 | | NS_IMETHODIMP |
1271 | | nsXULAppInfo::RegisterAppMemory(uint64_t pointer, |
1272 | | uint64_t len) |
1273 | 0 | { |
1274 | 0 | return CrashReporter::RegisterAppMemory((void *)pointer, len); |
1275 | 0 | } |
1276 | | |
1277 | | NS_IMETHODIMP |
1278 | | nsXULAppInfo::WriteMinidumpForException(void* aExceptionInfo) |
1279 | 0 | { |
1280 | | #ifdef XP_WIN32 |
1281 | | return CrashReporter::WriteMinidumpForException(static_cast<EXCEPTION_POINTERS*>(aExceptionInfo)); |
1282 | | #else |
1283 | | return NS_ERROR_NOT_IMPLEMENTED; |
1284 | 0 | #endif |
1285 | 0 | } |
1286 | | |
1287 | | NS_IMETHODIMP |
1288 | | nsXULAppInfo::AppendObjCExceptionInfoToAppNotes(void* aException) |
1289 | 0 | { |
1290 | | #ifdef XP_MACOSX |
1291 | | return CrashReporter::AppendObjCExceptionInfoToAppNotes(aException); |
1292 | | #else |
1293 | | return NS_ERROR_NOT_IMPLEMENTED; |
1294 | 0 | #endif |
1295 | 0 | } |
1296 | | |
1297 | | NS_IMETHODIMP |
1298 | | nsXULAppInfo::GetSubmitReports(bool* aEnabled) |
1299 | 0 | { |
1300 | 0 | return CrashReporter::GetSubmitReports(aEnabled); |
1301 | 0 | } |
1302 | | |
1303 | | NS_IMETHODIMP |
1304 | | nsXULAppInfo::SetSubmitReports(bool aEnabled) |
1305 | 0 | { |
1306 | 0 | return CrashReporter::SetSubmitReports(aEnabled); |
1307 | 0 | } |
1308 | | |
1309 | | NS_IMETHODIMP |
1310 | | nsXULAppInfo::UpdateCrashEventsDir() |
1311 | 0 | { |
1312 | 0 | CrashReporter::UpdateCrashEventsDir(); |
1313 | 0 | return NS_OK; |
1314 | 0 | } |
1315 | | |
1316 | | NS_IMETHODIMP |
1317 | | nsXULAppInfo::SaveMemoryReport() |
1318 | 0 | { |
1319 | 0 | if (!CrashReporter::GetEnabled()) { |
1320 | 0 | return NS_ERROR_NOT_INITIALIZED; |
1321 | 0 | } |
1322 | 0 | nsCOMPtr<nsIFile> file; |
1323 | 0 | nsresult rv = CrashReporter::GetDefaultMemoryReportFile(getter_AddRefs(file)); |
1324 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
1325 | 0 | return rv; |
1326 | 0 | } |
1327 | 0 | |
1328 | 0 | nsString path; |
1329 | 0 | file->GetPath(path); |
1330 | 0 |
|
1331 | 0 | nsCOMPtr<nsIMemoryInfoDumper> dumper = |
1332 | 0 | do_GetService("@mozilla.org/memory-info-dumper;1"); |
1333 | 0 | if (NS_WARN_IF(!dumper)) { |
1334 | 0 | return NS_ERROR_UNEXPECTED; |
1335 | 0 | } |
1336 | 0 | |
1337 | 0 | rv = dumper->DumpMemoryReportsToNamedFile(path, this, file, true /* anonymize */); |
1338 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
1339 | 0 | return rv; |
1340 | 0 | } |
1341 | 0 | return NS_OK; |
1342 | 0 | } |
1343 | | |
1344 | | NS_IMETHODIMP |
1345 | | nsXULAppInfo::SetTelemetrySessionId(const nsACString& id) |
1346 | 0 | { |
1347 | 0 | CrashReporter::SetTelemetrySessionId(id); |
1348 | 0 | return NS_OK; |
1349 | 0 | } |
1350 | | |
1351 | | // This method is from nsIFInishDumpingCallback. |
1352 | | NS_IMETHODIMP |
1353 | | nsXULAppInfo::Callback(nsISupports* aData) |
1354 | 0 | { |
1355 | 0 | nsCOMPtr<nsIFile> file = do_QueryInterface(aData); |
1356 | 0 | MOZ_ASSERT(file); |
1357 | 0 |
|
1358 | 0 | CrashReporter::SetMemoryReportFile(file); |
1359 | 0 | return NS_OK; |
1360 | 0 | } |
1361 | | |
1362 | | static const nsXULAppInfo kAppInfo; |
1363 | | static nsresult AppInfoConstructor(nsISupports* aOuter, |
1364 | | REFNSIID aIID, void **aResult) |
1365 | 3 | { |
1366 | 3 | NS_ENSURE_NO_AGGREGATION(aOuter); |
1367 | 3 | |
1368 | 3 | return const_cast<nsXULAppInfo*>(&kAppInfo)-> |
1369 | 3 | QueryInterface(aIID, aResult); |
1370 | 3 | } |
1371 | | |
1372 | | bool gLogConsoleErrors = false; |
1373 | | |
1374 | | #define NS_ENSURE_TRUE_LOG(x, ret) \ |
1375 | 0 | PR_BEGIN_MACRO \ |
1376 | 0 | if (MOZ_UNLIKELY(!(x))) { \ |
1377 | 0 | NS_WARNING("NS_ENSURE_TRUE(" #x ") failed"); \ |
1378 | 0 | gLogConsoleErrors = true; \ |
1379 | 0 | return ret; \ |
1380 | 0 | } \ |
1381 | 0 | PR_END_MACRO |
1382 | | |
1383 | | #define NS_ENSURE_SUCCESS_LOG(res, ret) \ |
1384 | 0 | NS_ENSURE_TRUE_LOG(NS_SUCCEEDED(res), ret) |
1385 | | |
1386 | | /** |
1387 | | * Because we're starting/stopping XPCOM several times in different scenarios, |
1388 | | * this class is a stack-based critter that makes sure that XPCOM is shut down |
1389 | | * during early returns. |
1390 | | */ |
1391 | | |
1392 | | class ScopedXPCOMStartup |
1393 | | { |
1394 | | public: |
1395 | | ScopedXPCOMStartup() : |
1396 | 0 | mServiceManager(nullptr) { } |
1397 | | ~ScopedXPCOMStartup(); |
1398 | | |
1399 | | nsresult Initialize(); |
1400 | | nsresult SetWindowCreator(nsINativeAppSupport* native); |
1401 | | |
1402 | | private: |
1403 | | nsIServiceManager* mServiceManager; |
1404 | | static nsINativeAppSupport* gNativeAppSupport; |
1405 | | |
1406 | | friend already_AddRefed<nsINativeAppSupport> NS_GetNativeAppSupport(); |
1407 | | }; |
1408 | | |
1409 | | ScopedXPCOMStartup::~ScopedXPCOMStartup() |
1410 | 0 | { |
1411 | 0 | NS_IF_RELEASE(gNativeAppSupport); |
1412 | 0 |
|
1413 | 0 | if (mServiceManager) { |
1414 | | #ifdef XP_MACOSX |
1415 | | // On OS X, we need a pool to catch cocoa objects that are autoreleased |
1416 | | // during teardown. |
1417 | | mozilla::MacAutoreleasePool pool; |
1418 | | #endif |
1419 | |
|
1420 | 0 | nsCOMPtr<nsIAppStartup> appStartup (do_GetService(NS_APPSTARTUP_CONTRACTID)); |
1421 | 0 | if (appStartup) |
1422 | 0 | appStartup->DestroyHiddenWindow(); |
1423 | 0 |
|
1424 | 0 | gDirServiceProvider->DoShutdown(); |
1425 | 0 | PROFILER_ADD_MARKER("Shutdown early"); |
1426 | 0 |
|
1427 | 0 | WriteConsoleLog(); |
1428 | 0 |
|
1429 | 0 | NS_ShutdownXPCOM(mServiceManager); |
1430 | 0 | mServiceManager = nullptr; |
1431 | 0 | } |
1432 | 0 | } |
1433 | | |
1434 | | // {95d89e3e-a169-41a3-8e56-719978e15b12} |
1435 | | #define APPINFO_CID \ |
1436 | | { 0x95d89e3e, 0xa169, 0x41a3, { 0x8e, 0x56, 0x71, 0x99, 0x78, 0xe1, 0x5b, 0x12 } } |
1437 | | |
1438 | | // {5F5E59CE-27BC-47eb-9D1F-B09CA9049836} |
1439 | | static const nsCID kProfileServiceCID = |
1440 | | { 0x5f5e59ce, 0x27bc, 0x47eb, { 0x9d, 0x1f, 0xb0, 0x9c, 0xa9, 0x4, 0x98, 0x36 } }; |
1441 | | |
1442 | | static already_AddRefed<nsIFactory> |
1443 | | ProfileServiceFactoryConstructor(const mozilla::Module& module, const mozilla::Module::CIDEntry& entry) |
1444 | 0 | { |
1445 | 0 | nsCOMPtr<nsIFactory> factory; |
1446 | 0 | NS_NewToolkitProfileFactory(getter_AddRefs(factory)); |
1447 | 0 | return factory.forget(); |
1448 | 0 | } |
1449 | | |
1450 | | NS_DEFINE_NAMED_CID(APPINFO_CID); |
1451 | | |
1452 | | static const mozilla::Module::CIDEntry kXRECIDs[] = { |
1453 | | { &kAPPINFO_CID, false, nullptr, AppInfoConstructor }, |
1454 | | { &kProfileServiceCID, false, ProfileServiceFactoryConstructor, nullptr }, |
1455 | | { nullptr } |
1456 | | }; |
1457 | | |
1458 | | static const mozilla::Module::ContractIDEntry kXREContracts[] = { |
1459 | | { XULAPPINFO_SERVICE_CONTRACTID, &kAPPINFO_CID }, |
1460 | | { XULRUNTIME_SERVICE_CONTRACTID, &kAPPINFO_CID }, |
1461 | | #ifdef MOZ_CRASHREPORTER |
1462 | | { NS_CRASHREPORTER_CONTRACTID, &kAPPINFO_CID }, |
1463 | | #endif // MOZ_CRASHREPORTER |
1464 | | { NS_PROFILESERVICE_CONTRACTID, &kProfileServiceCID }, |
1465 | | { nullptr } |
1466 | | }; |
1467 | | |
1468 | | static const mozilla::Module kXREModule = { |
1469 | | mozilla::Module::kVersion, |
1470 | | kXRECIDs, |
1471 | | kXREContracts |
1472 | | }; |
1473 | | |
1474 | | NSMODULE_DEFN(Apprunner) = &kXREModule; |
1475 | | |
1476 | | nsresult |
1477 | | ScopedXPCOMStartup::Initialize() |
1478 | 0 | { |
1479 | 0 | NS_ASSERTION(gDirServiceProvider, "Should not get here!"); |
1480 | 0 |
|
1481 | 0 | nsresult rv; |
1482 | 0 |
|
1483 | 0 | rv = NS_InitXPCOM2(&mServiceManager, gDirServiceProvider->GetAppDir(), |
1484 | 0 | gDirServiceProvider); |
1485 | 0 | if (NS_FAILED(rv)) { |
1486 | 0 | NS_ERROR("Couldn't start xpcom!"); |
1487 | 0 | mServiceManager = nullptr; |
1488 | 0 | } |
1489 | 0 | else { |
1490 | | #ifdef DEBUG |
1491 | | nsCOMPtr<nsIComponentRegistrar> reg = |
1492 | | do_QueryInterface(mServiceManager); |
1493 | | NS_ASSERTION(reg, "Service Manager doesn't QI to Registrar."); |
1494 | | #endif |
1495 | | } |
1496 | 0 |
|
1497 | 0 | return rv; |
1498 | 0 | } |
1499 | | |
1500 | | /** |
1501 | | * This is a little factory class that serves as a singleton-service-factory |
1502 | | * for the nativeappsupport object. |
1503 | | */ |
1504 | | class nsSingletonFactory final : public nsIFactory |
1505 | | { |
1506 | | public: |
1507 | | NS_DECL_ISUPPORTS |
1508 | | NS_DECL_NSIFACTORY |
1509 | | |
1510 | | explicit nsSingletonFactory(nsISupports* aSingleton); |
1511 | | |
1512 | | private: |
1513 | 0 | ~nsSingletonFactory() { } |
1514 | | nsCOMPtr<nsISupports> mSingleton; |
1515 | | }; |
1516 | | |
1517 | | nsSingletonFactory::nsSingletonFactory(nsISupports* aSingleton) |
1518 | | : mSingleton(aSingleton) |
1519 | 0 | { |
1520 | 0 | NS_ASSERTION(mSingleton, "Singleton was null!"); |
1521 | 0 | } |
1522 | | |
1523 | | NS_IMPL_ISUPPORTS(nsSingletonFactory, nsIFactory) |
1524 | | |
1525 | | NS_IMETHODIMP |
1526 | | nsSingletonFactory::CreateInstance(nsISupports* aOuter, |
1527 | | const nsIID& aIID, |
1528 | | void* *aResult) |
1529 | 0 | { |
1530 | 0 | NS_ENSURE_NO_AGGREGATION(aOuter); |
1531 | 0 |
|
1532 | 0 | return mSingleton->QueryInterface(aIID, aResult); |
1533 | 0 | } |
1534 | | |
1535 | | NS_IMETHODIMP |
1536 | | nsSingletonFactory::LockFactory(bool) |
1537 | 0 | { |
1538 | 0 | return NS_OK; |
1539 | 0 | } |
1540 | | |
1541 | | /** |
1542 | | * Set our windowcreator on the WindowWatcher service. |
1543 | | */ |
1544 | | nsresult |
1545 | | ScopedXPCOMStartup::SetWindowCreator(nsINativeAppSupport* native) |
1546 | 0 | { |
1547 | 0 | nsresult rv; |
1548 | 0 |
|
1549 | 0 | NS_IF_ADDREF(gNativeAppSupport = native); |
1550 | 0 |
|
1551 | 0 | // Inform the chrome registry about OS accessibility |
1552 | 0 | nsCOMPtr<nsIToolkitChromeRegistry> cr = |
1553 | 0 | mozilla::services::GetToolkitChromeRegistryService(); |
1554 | 0 |
|
1555 | 0 | if (cr) |
1556 | 0 | cr->CheckForOSAccessibility(); |
1557 | 0 |
|
1558 | 0 | nsCOMPtr<nsIWindowCreator> creator (do_GetService(NS_APPSTARTUP_CONTRACTID)); |
1559 | 0 | if (!creator) return NS_ERROR_UNEXPECTED; |
1560 | 0 | |
1561 | 0 | nsCOMPtr<nsIWindowWatcher> wwatch |
1562 | 0 | (do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv)); |
1563 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
1564 | 0 |
|
1565 | 0 | return wwatch->SetWindowCreator(creator); |
1566 | 0 | } |
1567 | | |
1568 | | /* static */ already_AddRefed<nsINativeAppSupport> |
1569 | | NS_GetNativeAppSupport() |
1570 | 0 | { |
1571 | 0 | if (!ScopedXPCOMStartup::gNativeAppSupport) { |
1572 | 0 | return nullptr; |
1573 | 0 | } |
1574 | 0 | |
1575 | 0 | return do_AddRef(ScopedXPCOMStartup::gNativeAppSupport); |
1576 | 0 | } |
1577 | | |
1578 | | nsINativeAppSupport* ScopedXPCOMStartup::gNativeAppSupport; |
1579 | | |
1580 | | static void DumpArbitraryHelp() |
1581 | 0 | { |
1582 | 0 | nsresult rv; |
1583 | 0 |
|
1584 | 0 | ScopedLogging log; |
1585 | 0 |
|
1586 | 0 | { |
1587 | 0 | ScopedXPCOMStartup xpcom; |
1588 | 0 | xpcom.Initialize(); |
1589 | 0 |
|
1590 | 0 | nsCOMPtr<nsICommandLineRunner> cmdline(new nsCommandLine()); |
1591 | 0 |
|
1592 | 0 | nsCString text; |
1593 | 0 | rv = cmdline->GetHelpText(text); |
1594 | 0 | if (NS_SUCCEEDED(rv)) |
1595 | 0 | printf("%s", text.get()); |
1596 | 0 | } |
1597 | 0 | } |
1598 | | |
1599 | | // English text needs to go into a dtd file. |
1600 | | // But when this is called we have no components etc. These strings must either be |
1601 | | // here, or in a native resource file. |
1602 | | static void |
1603 | | DumpHelp() |
1604 | 0 | { |
1605 | 0 | printf("Usage: %s [ options ... ] [URL]\n" |
1606 | 0 | " where options include:\n\n", gArgv[0]); |
1607 | 0 |
|
1608 | 0 | #ifdef MOZ_X11 |
1609 | 0 | printf("X11 options\n" |
1610 | 0 | " --display=DISPLAY X display to use\n" |
1611 | 0 | " --sync Make X calls synchronous\n"); |
1612 | 0 | #endif |
1613 | 0 | #ifdef XP_UNIX |
1614 | 0 | printf(" --g-fatal-warnings Make all warnings fatal\n" |
1615 | 0 | "\n%s options\n", (const char*) gAppData->name); |
1616 | 0 | #endif |
1617 | 0 |
|
1618 | 0 | printf(" -h or --help Print this message.\n" |
1619 | 0 | " -v or --version Print %s version.\n" |
1620 | 0 | " -P <profile> Start with <profile>.\n" |
1621 | 0 | " --profile <path> Start with profile at <path>.\n" |
1622 | 0 | " --migration Start with migration wizard.\n" |
1623 | 0 | " --ProfileManager Start with ProfileManager.\n" |
1624 | 0 | " --no-remote Do not accept or send remote commands; implies\n" |
1625 | 0 | " --new-instance.\n" |
1626 | 0 | " --new-instance Open new instance, not a new window in running instance.\n" |
1627 | 0 | " --UILocale <locale> Start with <locale> resources as UI Locale.\n" |
1628 | 0 | " --safe-mode Disables extensions and themes for this session.\n" |
1629 | 0 | " -MOZ_LOG=<modules> Treated as MOZ_LOG=<modules> environment variable, overrides it.\n" |
1630 | 0 | " -MOZ_LOG_FILE=<file> Treated as MOZ_LOG_FILE=<file> environment variable, overrides it.\n" |
1631 | 0 | " If MOZ_LOG_FILE is not specified as an argument or as an environment variable,\n" |
1632 | 0 | " logging will be written to stdout.\n" |
1633 | 0 | , (const char*)gAppData->name); |
1634 | 0 |
|
1635 | | #if defined(XP_WIN) |
1636 | | printf(" --console Start %s with a debugging console.\n", (const char*) gAppData->name); |
1637 | | #endif |
1638 | |
|
1639 | 0 | #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) || defined(XP_MACOSX) |
1640 | 0 | printf(" --headless Run without a GUI.\n"); |
1641 | 0 | #endif |
1642 | 0 |
|
1643 | 0 | printf(" --save-recordings Save recordings for all content processes to a directory.\n"); |
1644 | 0 |
|
1645 | 0 | // this works, but only after the components have registered. so if you drop in a new command line handler, --help |
1646 | 0 | // won't not until the second run. |
1647 | 0 | // out of the bug, because we ship a component.reg file, it works correctly. |
1648 | 0 | DumpArbitraryHelp(); |
1649 | 0 | } |
1650 | | |
1651 | | static inline void |
1652 | | DumpVersion() |
1653 | 0 | { |
1654 | 0 | if (gAppData->vendor) |
1655 | 0 | printf("%s ", (const char*) gAppData->vendor); |
1656 | 0 | printf("%s %s", (const char*) gAppData->name, (const char*) gAppData->version); |
1657 | 0 | if (gAppData->copyright) |
1658 | 0 | printf(", %s", (const char*) gAppData->copyright); |
1659 | 0 | printf("\n"); |
1660 | 0 | } |
1661 | | |
1662 | | #ifdef MOZ_ENABLE_XREMOTE |
1663 | | static RemoteResult |
1664 | | ParseRemoteCommandLine(nsCString& program, |
1665 | | const char** profile, |
1666 | | const char** username) |
1667 | 0 | { |
1668 | 0 | ArgResult ar; |
1669 | 0 |
|
1670 | 0 | ar = CheckArg("p", profile, CheckArgFlag::None); |
1671 | 0 | if (ar == ARG_BAD) { |
1672 | 0 | // Leave it to the normal command line handling to handle this situation. |
1673 | 0 | return REMOTE_NOT_FOUND; |
1674 | 0 | } |
1675 | 0 | |
1676 | 0 | const char *temp = nullptr; |
1677 | 0 | ar = CheckArg("a", &temp, CheckArgFlag::CheckOSInt | CheckArgFlag::RemoveArg); |
1678 | 0 | if (ar == ARG_BAD) { |
1679 | 0 | PR_fprintf(PR_STDERR, "Error: argument -a requires an application name\n"); |
1680 | 0 | return REMOTE_ARG_BAD; |
1681 | 0 | } |
1682 | 0 | if (ar == ARG_FOUND) { |
1683 | 0 | program.Assign(temp); |
1684 | 0 | } |
1685 | 0 |
|
1686 | 0 | ar = CheckArg("u", username, CheckArgFlag::CheckOSInt | CheckArgFlag::RemoveArg); |
1687 | 0 | if (ar == ARG_BAD) { |
1688 | 0 | PR_fprintf(PR_STDERR, "Error: argument -u requires a username\n"); |
1689 | 0 | return REMOTE_ARG_BAD; |
1690 | 0 | } |
1691 | 0 | |
1692 | 0 | return REMOTE_FOUND; |
1693 | 0 | } |
1694 | | |
1695 | | static RemoteResult |
1696 | | StartRemoteClient(const char* aDesktopStartupID, |
1697 | | nsCString& program, |
1698 | | const char* profile, |
1699 | | const char* username) |
1700 | 0 | { |
1701 | 0 | nsAutoPtr<nsRemoteClient> client; |
1702 | 0 |
|
1703 | | #if defined(MOZ_ENABLE_DBUS) && defined(MOZ_WAYLAND) |
1704 | | client = new DBusRemoteClient(); |
1705 | | #else |
1706 | | client = new XRemoteClient(); |
1707 | 0 | #endif |
1708 | 0 |
|
1709 | 0 | nsresult rv = client->Init(); |
1710 | 0 | if (NS_FAILED(rv)) |
1711 | 0 | return REMOTE_NOT_FOUND; |
1712 | 0 | |
1713 | 0 | nsCString response; |
1714 | 0 | bool success = false; |
1715 | 0 | rv = client->SendCommandLine(program.get(), username, profile, |
1716 | 0 | gArgc, gArgv, aDesktopStartupID, |
1717 | 0 | getter_Copies(response), &success); |
1718 | 0 | // did the command fail? |
1719 | 0 | if (!success) |
1720 | 0 | return REMOTE_NOT_FOUND; |
1721 | 0 | |
1722 | 0 | // The "command not parseable" error is returned when the |
1723 | 0 | // nsICommandLineHandler throws a NS_ERROR_ABORT. |
1724 | 0 | if (response.EqualsLiteral("500 command not parseable")) |
1725 | 0 | return REMOTE_ARG_BAD; |
1726 | 0 | |
1727 | 0 | if (NS_FAILED(rv)) |
1728 | 0 | return REMOTE_NOT_FOUND; |
1729 | 0 | |
1730 | 0 | return REMOTE_FOUND; |
1731 | 0 | } |
1732 | | #endif // MOZ_ENABLE_XREMOTE |
1733 | | |
1734 | | void |
1735 | | XRE_InitOmnijar(nsIFile* greOmni, nsIFile* appOmni) |
1736 | 0 | { |
1737 | 0 | mozilla::Omnijar::Init(greOmni, appOmni); |
1738 | 0 | } |
1739 | | |
1740 | | nsresult |
1741 | | XRE_GetBinaryPath(nsIFile* *aResult) |
1742 | 9 | { |
1743 | 9 | return mozilla::BinaryPath::GetFile(aResult); |
1744 | 9 | } |
1745 | | |
1746 | | #ifdef XP_WIN |
1747 | | #include "nsWindowsRestart.cpp" |
1748 | | #include <shellapi.h> |
1749 | | |
1750 | | typedef BOOL (WINAPI* SetProcessDEPPolicyFunc)(DWORD dwFlags); |
1751 | | |
1752 | | static void |
1753 | | RegisterApplicationRestartChanged(const char* aPref, void* aData) { |
1754 | | DWORD cchCmdLine = 0; |
1755 | | HRESULT rc = |
1756 | | ::GetApplicationRestartSettings(::GetCurrentProcess(), nullptr, &cchCmdLine, nullptr); |
1757 | | bool wasRegistered = false; |
1758 | | if (rc == S_OK) { |
1759 | | wasRegistered = true; |
1760 | | } |
1761 | | |
1762 | | if (Preferences::GetBool(PREF_WIN_REGISTER_APPLICATION_RESTART, false) && !wasRegistered) { |
1763 | | // Make the command line to use when restarting. |
1764 | | // Excludes argv[0] because RegisterApplicationRestart adds the |
1765 | | // executable name, replace that temporarily with -os-restarted |
1766 | | char* exeName = gRestartArgv[0]; |
1767 | | gRestartArgv[0] = const_cast<char*>("-os-restarted"); |
1768 | | wchar_t** restartArgvConverted = |
1769 | | AllocConvertUTF8toUTF16Strings(gRestartArgc, gRestartArgv); |
1770 | | gRestartArgv[0] = exeName; |
1771 | | |
1772 | | mozilla::UniquePtr<wchar_t[]> restartCommandLine; |
1773 | | if (restartArgvConverted) { |
1774 | | restartCommandLine = mozilla::MakeCommandLine(gRestartArgc, restartArgvConverted); |
1775 | | FreeAllocStrings(gRestartArgc, restartArgvConverted); |
1776 | | } |
1777 | | |
1778 | | if (restartCommandLine) { |
1779 | | // Flags RESTART_NO_PATCH and RESTART_NO_REBOOT are not set, so we |
1780 | | // should be restarted if terminated by an update or restart. |
1781 | | ::RegisterApplicationRestart(restartCommandLine.get(), RESTART_NO_CRASH | |
1782 | | RESTART_NO_HANG); |
1783 | | } |
1784 | | } else if (wasRegistered) { |
1785 | | ::UnregisterApplicationRestart(); |
1786 | | } |
1787 | | } |
1788 | | #endif // XP_WIN |
1789 | | |
1790 | | // If aBlankCommandLine is true, then the application will be launched with a |
1791 | | // blank command line instead of being launched with the same command line that |
1792 | | // it was initially started with. |
1793 | | static nsresult LaunchChild(nsINativeAppSupport* aNative, |
1794 | | bool aBlankCommandLine = false) |
1795 | 0 | { |
1796 | 0 | aNative->Quit(); // release DDE mutex, if we're holding it |
1797 | 0 |
|
1798 | 0 | // Restart this process by exec'ing it into the current process |
1799 | 0 | // if supported by the platform. Otherwise, use NSPR. |
1800 | 0 |
|
1801 | | #ifdef MOZ_JPROF |
1802 | | // make sure JPROF doesn't think we're E10s |
1803 | | unsetenv("JPROF_SLAVE"); |
1804 | | #endif |
1805 | |
|
1806 | 0 | if (aBlankCommandLine) { |
1807 | 0 | gRestartArgc = 1; |
1808 | 0 | gRestartArgv[gRestartArgc] = nullptr; |
1809 | 0 | } |
1810 | 0 |
|
1811 | 0 | SaveToEnv("MOZ_LAUNCHED_CHILD=1"); |
1812 | | #if defined(MOZ_LAUNCHER_PROCESS) |
1813 | | SaveToEnv("MOZ_LAUNCHER_PROCESS=1"); |
1814 | | #endif // defined(MOZ_LAUNCHER_PROCESS) |
1815 | |
|
1816 | 0 | #if !defined(MOZ_WIDGET_ANDROID) // Android has separate restart code. |
1817 | | #if defined(XP_MACOSX) |
1818 | | CommandLineServiceMac::SetupMacCommandLine(gRestartArgc, gRestartArgv, true); |
1819 | | LaunchChildMac(gRestartArgc, gRestartArgv); |
1820 | | #else |
1821 | | nsCOMPtr<nsIFile> lf; |
1822 | 0 | nsresult rv = XRE_GetBinaryPath(getter_AddRefs(lf)); |
1823 | 0 | if (NS_FAILED(rv)) |
1824 | 0 | return rv; |
1825 | 0 | |
1826 | | #if defined(XP_WIN) |
1827 | | nsAutoString exePath; |
1828 | | rv = lf->GetPath(exePath); |
1829 | | if (NS_FAILED(rv)) |
1830 | | return rv; |
1831 | | |
1832 | | HANDLE hProcess; |
1833 | | if (!WinLaunchChild(exePath.get(), gRestartArgc, gRestartArgv, nullptr, &hProcess)) |
1834 | | return NS_ERROR_FAILURE; |
1835 | | // Keep the current process around until the restarted process has created |
1836 | | // its message queue, to avoid the launched process's windows being forced |
1837 | | // into the background. |
1838 | | mozilla::WaitForInputIdle(hProcess); |
1839 | | ::CloseHandle(hProcess); |
1840 | | |
1841 | | #else |
1842 | 0 | nsAutoCString exePath; |
1843 | 0 | rv = lf->GetNativePath(exePath); |
1844 | 0 | if (NS_FAILED(rv)) |
1845 | 0 | return rv; |
1846 | 0 | |
1847 | 0 | #if defined(XP_UNIX) |
1848 | 0 | if (execv(exePath.get(), gRestartArgv) == -1) |
1849 | 0 | return NS_ERROR_FAILURE; |
1850 | | #else |
1851 | | PRProcess* process = PR_CreateProcess(exePath.get(), gRestartArgv, |
1852 | | nullptr, nullptr); |
1853 | | if (!process) return NS_ERROR_FAILURE; |
1854 | | |
1855 | | int32_t exitCode; |
1856 | | PRStatus failed = PR_WaitProcess(process, &exitCode); |
1857 | | if (failed || exitCode) |
1858 | | return NS_ERROR_FAILURE; |
1859 | | #endif // XP_UNIX |
1860 | | #endif // WP_WIN |
1861 | 0 | #endif // WP_MACOSX |
1862 | 0 | #endif // MOZ_WIDGET_ANDROID |
1863 | 0 | |
1864 | 0 | return NS_ERROR_LAUNCHED_CHILD_PROCESS; |
1865 | 0 | } |
1866 | | |
1867 | | static const char kProfileProperties[] = |
1868 | | "chrome://mozapps/locale/profile/profileSelection.properties"; |
1869 | | |
1870 | | namespace { |
1871 | | |
1872 | | /** |
1873 | | * This class, instead of a raw nsresult, should be the return type of any |
1874 | | * function called by SelectProfile that initializes XPCOM. |
1875 | | */ |
1876 | | class ReturnAbortOnError |
1877 | | { |
1878 | | public: |
1879 | | MOZ_IMPLICIT ReturnAbortOnError(nsresult aRv) |
1880 | 0 | { |
1881 | 0 | mRv = ConvertRv(aRv); |
1882 | 0 | } |
1883 | | |
1884 | | operator nsresult() |
1885 | 0 | { |
1886 | 0 | return mRv; |
1887 | 0 | } |
1888 | | |
1889 | | private: |
1890 | | inline nsresult |
1891 | | ConvertRv(nsresult aRv) |
1892 | 0 | { |
1893 | 0 | if (NS_SUCCEEDED(aRv) || aRv == NS_ERROR_LAUNCHED_CHILD_PROCESS) { |
1894 | 0 | return aRv; |
1895 | 0 | } |
1896 | 0 | return NS_ERROR_ABORT; |
1897 | 0 | } |
1898 | | |
1899 | | nsresult mRv; |
1900 | | }; |
1901 | | |
1902 | | } // namespace |
1903 | | |
1904 | | static ReturnAbortOnError |
1905 | | ProfileLockedDialog(nsIFile* aProfileDir, nsIFile* aProfileLocalDir, |
1906 | | nsIProfileUnlocker* aUnlocker, |
1907 | | nsINativeAppSupport* aNative, nsIProfileLock* *aResult) |
1908 | 0 | { |
1909 | 0 | nsresult rv; |
1910 | 0 |
|
1911 | 0 | ScopedXPCOMStartup xpcom; |
1912 | 0 | rv = xpcom.Initialize(); |
1913 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
1914 | 0 |
|
1915 | 0 | mozilla::Telemetry::WriteFailedProfileLock(aProfileDir); |
1916 | 0 |
|
1917 | 0 | rv = xpcom.SetWindowCreator(aNative); |
1918 | 0 | NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); |
1919 | 0 |
|
1920 | 0 | { //extra scoping is needed so we release these components before xpcom shutdown |
1921 | 0 | nsCOMPtr<nsIStringBundleService> sbs = |
1922 | 0 | mozilla::services::GetStringBundleService(); |
1923 | 0 | NS_ENSURE_TRUE(sbs, NS_ERROR_FAILURE); |
1924 | 0 |
|
1925 | 0 | nsCOMPtr<nsIStringBundle> sb; |
1926 | 0 | sbs->CreateBundle(kProfileProperties, getter_AddRefs(sb)); |
1927 | 0 | NS_ENSURE_TRUE_LOG(sbs, NS_ERROR_FAILURE); |
1928 | 0 |
|
1929 | 0 | NS_ConvertUTF8toUTF16 appName(gAppData->name); |
1930 | 0 | const char16_t* params[] = {appName.get(), appName.get()}; |
1931 | 0 |
|
1932 | 0 | nsAutoString killMessage; |
1933 | 0 | #ifndef XP_MACOSX |
1934 | 0 | rv = sb->FormatStringFromName(aUnlocker ? "restartMessageUnlocker" |
1935 | 0 | : "restartMessageNoUnlocker", |
1936 | 0 | params, 2, killMessage); |
1937 | | #else |
1938 | | rv = sb->FormatStringFromName(aUnlocker ? "restartMessageUnlockerMac" |
1939 | | : "restartMessageNoUnlockerMac", |
1940 | | params, 2, killMessage); |
1941 | | #endif |
1942 | 0 | NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); |
1943 | 0 |
|
1944 | 0 | nsAutoString killTitle; |
1945 | 0 | rv = sb->FormatStringFromName("restartTitle", params, 1, killTitle); |
1946 | 0 | NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); |
1947 | 0 |
|
1948 | 0 | if (gfxPlatform::IsHeadless()) { |
1949 | 0 | // TODO: make a way to turn off all dialogs when headless. |
1950 | 0 | Output(true, "%s\n", NS_LossyConvertUTF16toASCII(killMessage).get()); |
1951 | 0 | return NS_ERROR_FAILURE; |
1952 | 0 | } |
1953 | 0 | |
1954 | 0 | nsCOMPtr<nsIPromptService> ps |
1955 | 0 | (do_GetService(NS_PROMPTSERVICE_CONTRACTID)); |
1956 | 0 | NS_ENSURE_TRUE(ps, NS_ERROR_FAILURE); |
1957 | 0 |
|
1958 | 0 | if (aUnlocker) { |
1959 | 0 | int32_t button; |
1960 | | #ifdef MOZ_WIDGET_ANDROID |
1961 | | java::GeckoAppShell::KillAnyZombies(); |
1962 | | button = 0; |
1963 | | #else |
1964 | | const uint32_t flags = |
1965 | 0 | (nsIPromptService::BUTTON_TITLE_IS_STRING * |
1966 | 0 | nsIPromptService::BUTTON_POS_0) + |
1967 | 0 | (nsIPromptService::BUTTON_TITLE_CANCEL * |
1968 | 0 | nsIPromptService::BUTTON_POS_1); |
1969 | 0 |
|
1970 | 0 | bool checkState = false; |
1971 | 0 | rv = ps->ConfirmEx(nullptr, killTitle.get(), killMessage.get(), flags, |
1972 | 0 | killTitle.get(), nullptr, nullptr, nullptr, |
1973 | 0 | &checkState, &button); |
1974 | 0 | NS_ENSURE_SUCCESS_LOG(rv, rv); |
1975 | 0 | #endif |
1976 | 0 |
|
1977 | 0 | if (button == 0) { |
1978 | 0 | rv = aUnlocker->Unlock(nsIProfileUnlocker::FORCE_QUIT); |
1979 | 0 | if (NS_FAILED(rv)) { |
1980 | 0 | return rv; |
1981 | 0 | } |
1982 | 0 | |
1983 | 0 | SaveFileToEnv("XRE_PROFILE_PATH", aProfileDir); |
1984 | 0 | SaveFileToEnv("XRE_PROFILE_LOCAL_PATH", aProfileLocalDir); |
1985 | 0 |
|
1986 | 0 | return LaunchChild(aNative); |
1987 | 0 | } |
1988 | 0 | } else { |
1989 | | #ifdef MOZ_WIDGET_ANDROID |
1990 | | if (java::GeckoAppShell::UnlockProfile()) { |
1991 | | return NS_LockProfilePath(aProfileDir, aProfileLocalDir, |
1992 | | nullptr, aResult); |
1993 | | } |
1994 | | #else |
1995 | | rv = ps->Alert(nullptr, killTitle.get(), killMessage.get()); |
1996 | 0 | NS_ENSURE_SUCCESS_LOG(rv, rv); |
1997 | 0 | #endif |
1998 | 0 | } |
1999 | 0 |
|
2000 | 0 | return NS_ERROR_ABORT; |
2001 | 0 | } |
2002 | 0 | } |
2003 | | |
2004 | | static nsresult |
2005 | | ProfileMissingDialog(nsINativeAppSupport* aNative) |
2006 | 0 | { |
2007 | 0 | nsresult rv; |
2008 | 0 |
|
2009 | 0 | ScopedXPCOMStartup xpcom; |
2010 | 0 | rv = xpcom.Initialize(); |
2011 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
2012 | 0 |
|
2013 | 0 | rv = xpcom.SetWindowCreator(aNative); |
2014 | 0 | NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); |
2015 | 0 |
|
2016 | 0 | { //extra scoping is needed so we release these components before xpcom shutdown |
2017 | 0 | nsCOMPtr<nsIStringBundleService> sbs = |
2018 | 0 | mozilla::services::GetStringBundleService(); |
2019 | 0 | NS_ENSURE_TRUE(sbs, NS_ERROR_FAILURE); |
2020 | 0 |
|
2021 | 0 | nsCOMPtr<nsIStringBundle> sb; |
2022 | 0 | sbs->CreateBundle(kProfileProperties, getter_AddRefs(sb)); |
2023 | 0 | NS_ENSURE_TRUE_LOG(sbs, NS_ERROR_FAILURE); |
2024 | 0 |
|
2025 | 0 | NS_ConvertUTF8toUTF16 appName(gAppData->name); |
2026 | 0 | const char16_t* params[] = {appName.get(), appName.get()}; |
2027 | 0 |
|
2028 | 0 | // profileMissing |
2029 | 0 | nsAutoString missingMessage; |
2030 | 0 | rv = sb->FormatStringFromName("profileMissing", params, 2, missingMessage); |
2031 | 0 | NS_ENSURE_SUCCESS(rv, NS_ERROR_ABORT); |
2032 | 0 |
|
2033 | 0 | nsAutoString missingTitle; |
2034 | 0 | rv = sb->FormatStringFromName("profileMissingTitle", params, 1, missingTitle); |
2035 | 0 | NS_ENSURE_SUCCESS(rv, NS_ERROR_ABORT); |
2036 | 0 |
|
2037 | 0 | nsCOMPtr<nsIPromptService> ps(do_GetService(NS_PROMPTSERVICE_CONTRACTID)); |
2038 | 0 | NS_ENSURE_TRUE(ps, NS_ERROR_FAILURE); |
2039 | 0 |
|
2040 | 0 | ps->Alert(nullptr, missingTitle.get(), missingMessage.get()); |
2041 | 0 |
|
2042 | 0 | return NS_ERROR_ABORT; |
2043 | 0 | } |
2044 | 0 | } |
2045 | | |
2046 | | static nsresult |
2047 | | ProfileLockedDialog(nsIToolkitProfile* aProfile, nsIProfileUnlocker* aUnlocker, |
2048 | | nsINativeAppSupport* aNative, nsIProfileLock* *aResult) |
2049 | 0 | { |
2050 | 0 | nsCOMPtr<nsIFile> profileDir; |
2051 | 0 | nsresult rv = aProfile->GetRootDir(getter_AddRefs(profileDir)); |
2052 | 0 | if (NS_FAILED(rv)) return rv; |
2053 | 0 | |
2054 | 0 | bool exists; |
2055 | 0 | profileDir->Exists(&exists); |
2056 | 0 | if (!exists) { |
2057 | 0 | return ProfileMissingDialog(aNative); |
2058 | 0 | } |
2059 | 0 | |
2060 | 0 | nsCOMPtr<nsIFile> profileLocalDir; |
2061 | 0 | rv = aProfile->GetLocalDir(getter_AddRefs(profileLocalDir)); |
2062 | 0 | if (NS_FAILED(rv)) return rv; |
2063 | 0 | |
2064 | 0 | return ProfileLockedDialog(profileDir, profileLocalDir, aUnlocker, aNative, |
2065 | 0 | aResult); |
2066 | 0 | } |
2067 | | |
2068 | | static const char kProfileManagerURL[] = |
2069 | | "chrome://mozapps/content/profile/profileSelection.xul"; |
2070 | | |
2071 | | static ReturnAbortOnError |
2072 | | ShowProfileManager(nsIToolkitProfileService* aProfileSvc, |
2073 | | nsINativeAppSupport* aNative) |
2074 | 0 | { |
2075 | 0 | nsresult rv; |
2076 | 0 |
|
2077 | 0 | nsCOMPtr<nsIFile> profD, profLD; |
2078 | 0 | char16_t* profileNamePtr; |
2079 | 0 | nsAutoCString profileName; |
2080 | 0 | bool offline = false; |
2081 | 0 |
|
2082 | 0 | { |
2083 | 0 | ScopedXPCOMStartup xpcom; |
2084 | 0 | rv = xpcom.Initialize(); |
2085 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
2086 | 0 |
|
2087 | 0 | // Initialize the graphics prefs, some of the paths need them before |
2088 | 0 | // any other graphics is initialized (e.g., showing the profile chooser.) |
2089 | 0 | gfxPrefs::GetSingleton(); |
2090 | 0 |
|
2091 | 0 | rv = xpcom.SetWindowCreator(aNative); |
2092 | 0 | NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); |
2093 | 0 |
|
2094 | | #ifdef XP_MACOSX |
2095 | | CommandLineServiceMac::SetupMacCommandLine(gRestartArgc, gRestartArgv, true); |
2096 | | #endif |
2097 | |
|
2098 | | #ifdef XP_WIN |
2099 | | // we don't have to wait here because profile manager window will pump |
2100 | | // and DDE message will be handled |
2101 | | ProcessDDE(aNative, false); |
2102 | | #endif |
2103 | |
|
2104 | 0 | { //extra scoping is needed so we release these components before xpcom shutdown |
2105 | 0 | nsCOMPtr<nsIWindowWatcher> windowWatcher |
2106 | 0 | (do_GetService(NS_WINDOWWATCHER_CONTRACTID)); |
2107 | 0 | nsCOMPtr<nsIDialogParamBlock> ioParamBlock |
2108 | 0 | (do_CreateInstance(NS_DIALOGPARAMBLOCK_CONTRACTID)); |
2109 | 0 | nsCOMPtr<nsIMutableArray> dlgArray (do_CreateInstance(NS_ARRAY_CONTRACTID)); |
2110 | 0 | NS_ENSURE_TRUE(windowWatcher && ioParamBlock && dlgArray, NS_ERROR_FAILURE); |
2111 | 0 |
|
2112 | 0 | ioParamBlock->SetObjects(dlgArray); |
2113 | 0 |
|
2114 | 0 | nsCOMPtr<nsIAppStartup> appStartup |
2115 | 0 | (do_GetService(NS_APPSTARTUP_CONTRACTID)); |
2116 | 0 | NS_ENSURE_TRUE(appStartup, NS_ERROR_FAILURE); |
2117 | 0 |
|
2118 | 0 | nsCOMPtr<mozIDOMWindowProxy> newWindow; |
2119 | 0 | rv = windowWatcher->OpenWindow(nullptr, |
2120 | 0 | kProfileManagerURL, |
2121 | 0 | "_blank", |
2122 | 0 | "centerscreen,chrome,modal,titlebar", |
2123 | 0 | ioParamBlock, |
2124 | 0 | getter_AddRefs(newWindow)); |
2125 | 0 |
|
2126 | 0 | NS_ENSURE_SUCCESS_LOG(rv, rv); |
2127 | 0 |
|
2128 | 0 | aProfileSvc->Flush(); |
2129 | 0 |
|
2130 | 0 | int32_t dialogConfirmed; |
2131 | 0 | rv = ioParamBlock->GetInt(0, &dialogConfirmed); |
2132 | 0 | if (NS_FAILED(rv) || dialogConfirmed == 0) return NS_ERROR_ABORT; |
2133 | 0 | |
2134 | 0 | int32_t startOffline; |
2135 | 0 | rv = ioParamBlock->GetInt(1, &startOffline); |
2136 | 0 | offline = NS_SUCCEEDED(rv) && startOffline == 1; |
2137 | 0 |
|
2138 | 0 | nsCOMPtr<nsIProfileLock> lock; |
2139 | 0 | rv = dlgArray->QueryElementAt(0, NS_GET_IID(nsIProfileLock), |
2140 | 0 | getter_AddRefs(lock)); |
2141 | 0 | NS_ENSURE_SUCCESS_LOG(rv, rv); |
2142 | 0 |
|
2143 | 0 | rv = lock->GetDirectory(getter_AddRefs(profD)); |
2144 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
2145 | 0 |
|
2146 | 0 | rv = lock->GetLocalDirectory(getter_AddRefs(profLD)); |
2147 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
2148 | 0 |
|
2149 | 0 | rv = ioParamBlock->GetString(0, &profileNamePtr); |
2150 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
2151 | 0 |
|
2152 | 0 | CopyUTF16toUTF8(MakeStringSpan(profileNamePtr), profileName); |
2153 | 0 | free(profileNamePtr); |
2154 | 0 |
|
2155 | 0 | lock->Unlock(); |
2156 | 0 | } |
2157 | 0 | } |
2158 | 0 |
|
2159 | 0 | SaveFileToEnv("XRE_PROFILE_PATH", profD); |
2160 | 0 | SaveFileToEnv("XRE_PROFILE_LOCAL_PATH", profLD); |
2161 | 0 | SaveWordToEnv("XRE_PROFILE_NAME", profileName); |
2162 | 0 |
|
2163 | 0 | if (offline) { |
2164 | 0 | SaveToEnv("XRE_START_OFFLINE=1"); |
2165 | 0 | } |
2166 | 0 | if (gRestartedByOS) { |
2167 | 0 | // Re-add this argument when actually starting the application. |
2168 | 0 | char** newArgv = (char**) realloc(gRestartArgv, sizeof(char*) * (gRestartArgc + 2)); |
2169 | 0 | NS_ENSURE_TRUE(newArgv, NS_ERROR_OUT_OF_MEMORY); |
2170 | 0 | gRestartArgv = newArgv; |
2171 | 0 | gRestartArgv[gRestartArgc++] = const_cast<char*>("-os-restarted"); |
2172 | 0 | gRestartArgv[gRestartArgc] = nullptr; |
2173 | 0 | } |
2174 | 0 |
|
2175 | 0 | return LaunchChild(aNative); |
2176 | 0 | } |
2177 | | |
2178 | | /** |
2179 | | * Get the currently running profile using its root directory. |
2180 | | * |
2181 | | * @param aProfileSvc The profile service |
2182 | | * @param aCurrentProfileRoot The root directory of the current profile. |
2183 | | * @param aProfile Out-param that returns the profile object. |
2184 | | * @return an error if aCurrentProfileRoot is not found |
2185 | | */ |
2186 | | static nsresult |
2187 | | GetCurrentProfile(nsIToolkitProfileService* aProfileSvc, |
2188 | | nsIFile* aCurrentProfileRoot, |
2189 | | nsIToolkitProfile** aProfile) |
2190 | 0 | { |
2191 | 0 | NS_ENSURE_ARG_POINTER(aProfileSvc); |
2192 | 0 | NS_ENSURE_ARG_POINTER(aProfile); |
2193 | 0 |
|
2194 | 0 | nsCOMPtr<nsISimpleEnumerator> profiles; |
2195 | 0 | nsresult rv = aProfileSvc->GetProfiles(getter_AddRefs(profiles)); |
2196 | 0 | if (NS_FAILED(rv)) |
2197 | 0 | return rv; |
2198 | 0 | |
2199 | 0 | bool foundMatchingProfile = false; |
2200 | 0 | nsCOMPtr<nsISupports> supports; |
2201 | 0 | rv = profiles->GetNext(getter_AddRefs(supports)); |
2202 | 0 | while (NS_SUCCEEDED(rv)) { |
2203 | 0 | nsCOMPtr<nsIToolkitProfile> profile = do_QueryInterface(supports); |
2204 | 0 | nsCOMPtr<nsIFile> profileRoot; |
2205 | 0 | profile->GetRootDir(getter_AddRefs(profileRoot)); |
2206 | 0 | profileRoot->Equals(aCurrentProfileRoot, &foundMatchingProfile); |
2207 | 0 | if (foundMatchingProfile) { |
2208 | 0 | profile.forget(aProfile); |
2209 | 0 | return NS_OK; |
2210 | 0 | } |
2211 | 0 | rv = profiles->GetNext(getter_AddRefs(supports)); |
2212 | 0 | } |
2213 | 0 | return rv; |
2214 | 0 | } |
2215 | | |
2216 | | static bool gDoMigration = false; |
2217 | | static bool gDoProfileReset = false; |
2218 | | static nsAutoCString gResetOldProfileName; |
2219 | | |
2220 | | // Pick a profile. We need to end up with a profile lock. |
2221 | | // |
2222 | | // 1) check for --profile <path> |
2223 | | // 2) check for -P <name> |
2224 | | // 3) check for --ProfileManager |
2225 | | // 4) use the default profile, if there is one |
2226 | | // 5) if there are *no* profiles, set up profile-migration |
2227 | | // 6) display the profile-manager UI |
2228 | | static nsresult |
2229 | | SelectProfile(nsIProfileLock* *aResult, nsIToolkitProfileService* aProfileSvc, nsINativeAppSupport* aNative, |
2230 | | bool* aStartOffline, nsACString* aProfileName) |
2231 | 0 | { |
2232 | 0 | StartupTimeline::Record(StartupTimeline::SELECT_PROFILE); |
2233 | 0 |
|
2234 | 0 | nsresult rv; |
2235 | 0 | ArgResult ar; |
2236 | 0 | const char* arg; |
2237 | 0 | *aResult = nullptr; |
2238 | 0 | *aStartOffline = false; |
2239 | 0 |
|
2240 | 0 | ar = CheckArg("offline", nullptr, CheckArgFlag::CheckOSInt | CheckArgFlag::RemoveArg); |
2241 | 0 | if (ar == ARG_BAD) { |
2242 | 0 | PR_fprintf(PR_STDERR, "Error: argument --offline is invalid when argument --osint is specified\n"); |
2243 | 0 | return NS_ERROR_FAILURE; |
2244 | 0 | } |
2245 | 0 | |
2246 | 0 | if (ar || EnvHasValue("XRE_START_OFFLINE")) |
2247 | 0 | *aStartOffline = true; |
2248 | 0 |
|
2249 | 0 | if (EnvHasValue("MOZ_RESET_PROFILE_RESTART")) { |
2250 | 0 | gDoProfileReset = true; |
2251 | 0 | gDoMigration = true; |
2252 | 0 | SaveToEnv("MOZ_RESET_PROFILE_RESTART="); |
2253 | 0 | // We only want to restore the previous session if the profile refresh was |
2254 | 0 | // triggered by user. And if it was a user-triggered profile refresh |
2255 | 0 | // through, say, the safeMode dialog or the troubleshooting page, the MOZ_RESET_PROFILE_RESTART |
2256 | 0 | // env variable would be set. Hence we set MOZ_RESET_PROFILE_MIGRATE_SESSION here so that |
2257 | 0 | // Firefox profile migrator would migrate old session data later. |
2258 | 0 | SaveToEnv("MOZ_RESET_PROFILE_MIGRATE_SESSION=1"); |
2259 | 0 | } |
2260 | 0 |
|
2261 | 0 | // reset-profile and migration args need to be checked before any profiles are chosen below. |
2262 | 0 | ar = CheckArg("reset-profile", nullptr, CheckArgFlag::CheckOSInt | CheckArgFlag::RemoveArg); |
2263 | 0 | if (ar == ARG_BAD) { |
2264 | 0 | PR_fprintf(PR_STDERR, "Error: argument --reset-profile is invalid when argument --osint is specified\n"); |
2265 | 0 | return NS_ERROR_FAILURE; |
2266 | 0 | } |
2267 | 0 | if (ar == ARG_FOUND) { |
2268 | 0 | gDoProfileReset = true; |
2269 | 0 | } |
2270 | 0 |
|
2271 | 0 | ar = CheckArg("migration", nullptr, CheckArgFlag::CheckOSInt | CheckArgFlag::RemoveArg); |
2272 | 0 | if (ar == ARG_BAD) { |
2273 | 0 | PR_fprintf(PR_STDERR, "Error: argument --migration is invalid when argument --osint is specified\n"); |
2274 | 0 | return NS_ERROR_FAILURE; |
2275 | 0 | } |
2276 | 0 | if (ar == ARG_FOUND) { |
2277 | 0 | gDoMigration = true; |
2278 | 0 | } |
2279 | 0 |
|
2280 | 0 | nsCOMPtr<nsIFile> lf = GetFileFromEnv("XRE_PROFILE_PATH"); |
2281 | 0 | if (lf) { |
2282 | 0 | nsCOMPtr<nsIFile> localDir = |
2283 | 0 | GetFileFromEnv("XRE_PROFILE_LOCAL_PATH"); |
2284 | 0 | if (!localDir) { |
2285 | 0 | localDir = lf; |
2286 | 0 | } |
2287 | 0 |
|
2288 | 0 | arg = PR_GetEnv("XRE_PROFILE_NAME"); |
2289 | 0 | if (arg && *arg && aProfileName) { |
2290 | 0 | aProfileName->Assign(nsDependentCString(arg)); |
2291 | 0 | if (gDoProfileReset) { |
2292 | 0 | gResetOldProfileName.Assign(*aProfileName); |
2293 | 0 | } |
2294 | 0 | } |
2295 | 0 |
|
2296 | 0 | // Clear out flags that we handled (or should have handled!) last startup. |
2297 | 0 | const char *dummy; |
2298 | 0 | CheckArg("p", &dummy); |
2299 | 0 | CheckArg("profile", &dummy); |
2300 | 0 | CheckArg("profilemanager"); |
2301 | 0 |
|
2302 | 0 | if (gDoProfileReset) { |
2303 | 0 | // If we're resetting a profile, create a new one and use it to startup. |
2304 | 0 | nsCOMPtr<nsIToolkitProfile> newProfile; |
2305 | 0 | rv = CreateResetProfile(aProfileSvc, gResetOldProfileName, getter_AddRefs(newProfile)); |
2306 | 0 | if (NS_SUCCEEDED(rv)) { |
2307 | 0 | rv = newProfile->GetRootDir(getter_AddRefs(lf)); |
2308 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
2309 | 0 | SaveFileToEnv("XRE_PROFILE_PATH", lf); |
2310 | 0 |
|
2311 | 0 | rv = newProfile->GetLocalDir(getter_AddRefs(localDir)); |
2312 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
2313 | 0 | SaveFileToEnv("XRE_PROFILE_LOCAL_PATH", localDir); |
2314 | 0 |
|
2315 | 0 | rv = newProfile->GetName(*aProfileName); |
2316 | 0 | if (NS_FAILED(rv)) |
2317 | 0 | aProfileName->Truncate(0); |
2318 | 0 | SaveWordToEnv("XRE_PROFILE_NAME", *aProfileName); |
2319 | 0 | } else { |
2320 | 0 | NS_WARNING("Profile reset failed."); |
2321 | 0 | gDoProfileReset = false; |
2322 | 0 | } |
2323 | 0 | } |
2324 | 0 |
|
2325 | 0 | return NS_LockProfilePath(lf, localDir, nullptr, aResult); |
2326 | 0 | } |
2327 | 0 | |
2328 | 0 | ar = CheckArg("profile", &arg, CheckArgFlag::CheckOSInt | CheckArgFlag::RemoveArg); |
2329 | 0 | if (ar == ARG_BAD) { |
2330 | 0 | PR_fprintf(PR_STDERR, "Error: argument --profile requires a path\n"); |
2331 | 0 | return NS_ERROR_FAILURE; |
2332 | 0 | } |
2333 | 0 | if (ar) { |
2334 | 0 | if (gDoProfileReset) { |
2335 | 0 | NS_WARNING("Profile reset is not supported in conjunction with --profile."); |
2336 | 0 | gDoProfileReset = false; |
2337 | 0 | } |
2338 | 0 |
|
2339 | 0 | nsCOMPtr<nsIFile> lf; |
2340 | 0 | rv = XRE_GetFileFromPath(arg, getter_AddRefs(lf)); |
2341 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
2342 | 0 |
|
2343 | 0 | nsCOMPtr<nsIProfileUnlocker> unlocker; |
2344 | 0 |
|
2345 | 0 | // Check if the profile path exists and it's a directory. |
2346 | 0 | bool exists; |
2347 | 0 | lf->Exists(&exists); |
2348 | 0 | if (!exists) { |
2349 | 0 | rv = lf->Create(nsIFile::DIRECTORY_TYPE, 0700); |
2350 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
2351 | 0 | } |
2352 | 0 |
|
2353 | 0 | // If a profile path is specified directory on the command line, then |
2354 | 0 | // assume that the temp directory is the same as the given directory. |
2355 | 0 | rv = NS_LockProfilePath(lf, lf, getter_AddRefs(unlocker), aResult); |
2356 | 0 | if (NS_SUCCEEDED(rv)) |
2357 | 0 | return rv; |
2358 | 0 | |
2359 | 0 | return ProfileLockedDialog(lf, lf, unlocker, aNative, aResult); |
2360 | 0 | } |
2361 | 0 | |
2362 | 0 | ar = CheckArg("createprofile", &arg, CheckArgFlag::CheckOSInt | CheckArgFlag::RemoveArg); |
2363 | 0 | if (ar == ARG_BAD) { |
2364 | 0 | PR_fprintf(PR_STDERR, "Error: argument --createprofile requires a profile name\n"); |
2365 | 0 | return NS_ERROR_FAILURE; |
2366 | 0 | } |
2367 | 0 | if (ar) { |
2368 | 0 | nsCOMPtr<nsIToolkitProfile> profile; |
2369 | 0 |
|
2370 | 0 | const char* delim = strchr(arg, ' '); |
2371 | 0 | if (delim) { |
2372 | 0 | nsCOMPtr<nsIFile> lf; |
2373 | 0 | rv = NS_NewNativeLocalFile(nsDependentCString(delim + 1), |
2374 | 0 | true, getter_AddRefs(lf)); |
2375 | 0 | if (NS_FAILED(rv)) { |
2376 | 0 | PR_fprintf(PR_STDERR, "Error: profile path not valid.\n"); |
2377 | 0 | return rv; |
2378 | 0 | } |
2379 | 0 | |
2380 | 0 | // As with --profile, assume that the given path will be used for the |
2381 | 0 | // main profile directory. |
2382 | 0 | rv = aProfileSvc->CreateProfile(lf, nsDependentCSubstring(arg, delim), |
2383 | 0 | getter_AddRefs(profile)); |
2384 | 0 | } else { |
2385 | 0 | rv = aProfileSvc->CreateProfile(nullptr, nsDependentCString(arg), |
2386 | 0 | getter_AddRefs(profile)); |
2387 | 0 | } |
2388 | 0 | // Some pathological arguments can make it this far |
2389 | 0 | if (NS_FAILED(rv)) { |
2390 | 0 | PR_fprintf(PR_STDERR, "Error creating profile.\n"); |
2391 | 0 | return rv; |
2392 | 0 | } |
2393 | 0 | rv = NS_ERROR_ABORT; |
2394 | 0 | aProfileSvc->Flush(); |
2395 | 0 |
|
2396 | 0 | // XXXben need to ensure prefs.js exists here so the tinderboxes will |
2397 | 0 | // not go orange. |
2398 | 0 | nsCOMPtr<nsIFile> prefsJSFile; |
2399 | 0 | profile->GetRootDir(getter_AddRefs(prefsJSFile)); |
2400 | 0 | prefsJSFile->AppendNative(NS_LITERAL_CSTRING("prefs.js")); |
2401 | 0 | PR_fprintf(PR_STDERR, "Success: created profile '%s' at '%s'\n", arg, |
2402 | 0 | prefsJSFile->HumanReadablePath().get()); |
2403 | 0 | bool exists; |
2404 | 0 | prefsJSFile->Exists(&exists); |
2405 | 0 | if (!exists) { |
2406 | 0 | // Ignore any errors; we're about to return NS_ERROR_ABORT anyway. |
2407 | 0 | Unused << prefsJSFile->Create(nsIFile::NORMAL_FILE_TYPE, 0644); |
2408 | 0 | } |
2409 | 0 | // XXXdarin perhaps 0600 would be better? |
2410 | 0 |
|
2411 | 0 | return rv; |
2412 | 0 | } |
2413 | 0 |
|
2414 | 0 | uint32_t count; |
2415 | 0 | rv = aProfileSvc->GetProfileCount(&count); |
2416 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
2417 | 0 |
|
2418 | 0 | ar = CheckArg("p", &arg); |
2419 | 0 | if (ar == ARG_BAD) { |
2420 | 0 | ar = CheckArg("osint"); |
2421 | 0 | if (ar == ARG_FOUND) { |
2422 | 0 | PR_fprintf(PR_STDERR, "Error: argument -p is invalid when argument --osint is specified\n"); |
2423 | 0 | return NS_ERROR_FAILURE; |
2424 | 0 | } |
2425 | 0 | |
2426 | 0 | return ShowProfileManager(aProfileSvc, aNative); |
2427 | 0 | } |
2428 | 0 | if (ar) { |
2429 | 0 | ar = CheckArg("osint"); |
2430 | 0 | if (ar == ARG_FOUND) { |
2431 | 0 | PR_fprintf(PR_STDERR, "Error: argument -p is invalid when argument --osint is specified\n"); |
2432 | 0 | return NS_ERROR_FAILURE; |
2433 | 0 | } |
2434 | 0 | nsCOMPtr<nsIToolkitProfile> profile; |
2435 | 0 | rv = aProfileSvc->GetProfileByName(nsDependentCString(arg), |
2436 | 0 | getter_AddRefs(profile)); |
2437 | 0 | if (NS_SUCCEEDED(rv)) { |
2438 | 0 | if (gDoProfileReset) { |
2439 | 0 | { |
2440 | 0 | // Check that the source profile is not in use by temporarily acquiring its lock. |
2441 | 0 | nsIProfileLock* tempProfileLock; |
2442 | 0 | nsCOMPtr<nsIProfileUnlocker> unlocker; |
2443 | 0 | rv = profile->Lock(getter_AddRefs(unlocker), &tempProfileLock); |
2444 | 0 | if (NS_FAILED(rv)) |
2445 | 0 | return ProfileLockedDialog(profile, unlocker, aNative, &tempProfileLock); |
2446 | 0 | } |
2447 | 0 | |
2448 | 0 | nsresult gotName = profile->GetName(gResetOldProfileName); |
2449 | 0 | if (NS_SUCCEEDED(gotName)) { |
2450 | 0 | nsCOMPtr<nsIToolkitProfile> newProfile; |
2451 | 0 | rv = CreateResetProfile(aProfileSvc, gResetOldProfileName, getter_AddRefs(newProfile)); |
2452 | 0 | if (NS_FAILED(rv)) { |
2453 | 0 | NS_WARNING("Failed to create a profile to reset to."); |
2454 | 0 | gDoProfileReset = false; |
2455 | 0 | } else { |
2456 | 0 | profile = newProfile; |
2457 | 0 | } |
2458 | 0 | } else { |
2459 | 0 | NS_WARNING("Failed to get the name of the profile we're resetting, so aborting reset."); |
2460 | 0 | gResetOldProfileName.Truncate(0); |
2461 | 0 | gDoProfileReset = false; |
2462 | 0 | } |
2463 | 0 | } |
2464 | 0 |
|
2465 | 0 | nsCOMPtr<nsIProfileUnlocker> unlocker; |
2466 | 0 | rv = profile->Lock(getter_AddRefs(unlocker), aResult); |
2467 | 0 | if (NS_SUCCEEDED(rv)) { |
2468 | 0 | if (aProfileName) |
2469 | 0 | aProfileName->Assign(nsDependentCString(arg)); |
2470 | 0 | return NS_OK; |
2471 | 0 | } |
2472 | 0 |
|
2473 | 0 | return ProfileLockedDialog(profile, unlocker, aNative, aResult); |
2474 | 0 | } |
2475 | 0 | |
2476 | 0 | return ShowProfileManager(aProfileSvc, aNative); |
2477 | 0 | } |
2478 | 0 | |
2479 | 0 | ar = CheckArg("profilemanager", nullptr, CheckArgFlag::CheckOSInt | CheckArgFlag::RemoveArg); |
2480 | 0 | if (ar == ARG_BAD) { |
2481 | 0 | PR_fprintf(PR_STDERR, "Error: argument --profilemanager is invalid when argument --osint is specified\n"); |
2482 | 0 | return NS_ERROR_FAILURE; |
2483 | 0 | } |
2484 | 0 | if (ar == ARG_FOUND) { |
2485 | 0 | return ShowProfileManager(aProfileSvc, aNative); |
2486 | 0 | } |
2487 | 0 | |
2488 | 0 | #ifndef MOZ_DEV_EDITION |
2489 | 0 | // If the only existing profile is the dev-edition-profile and this is not |
2490 | 0 | // Developer Edition, then no valid profiles were found. |
2491 | 0 | if (count == 1) { |
2492 | 0 | nsCOMPtr<nsIToolkitProfile> deProfile; |
2493 | 0 | // GetSelectedProfile will auto-select the only profile if there's just one |
2494 | 0 | aProfileSvc->GetSelectedProfile(getter_AddRefs(deProfile)); |
2495 | 0 | nsAutoCString profileName; |
2496 | 0 | deProfile->GetName(profileName); |
2497 | 0 | if (profileName.EqualsLiteral("dev-edition-default")) { |
2498 | 0 | count = 0; |
2499 | 0 | } |
2500 | 0 | } |
2501 | 0 | #endif |
2502 | 0 |
|
2503 | 0 | if (!count) { |
2504 | 0 | // For a fresh install, we would like to let users decide |
2505 | 0 | // to do profile migration on their own later after using. |
2506 | 0 | gDoMigration = false; |
2507 | 0 | gDoProfileReset = false; |
2508 | 0 |
|
2509 | 0 | // create a default profile |
2510 | 0 | nsCOMPtr<nsIToolkitProfile> profile; |
2511 | 0 | nsresult rv = aProfileSvc->CreateProfile(nullptr, // choose a default dir for us |
2512 | | #ifdef MOZ_DEV_EDITION |
2513 | | NS_LITERAL_CSTRING("dev-edition-default"), |
2514 | | #else |
2515 | 0 | NS_LITERAL_CSTRING("default"), |
2516 | 0 | #endif |
2517 | 0 | getter_AddRefs(profile)); |
2518 | 0 | if (NS_SUCCEEDED(rv)) { |
2519 | 0 | #ifndef MOZ_DEV_EDITION |
2520 | 0 | aProfileSvc->SetDefaultProfile(profile); |
2521 | 0 | #endif |
2522 | 0 | aProfileSvc->Flush(); |
2523 | 0 | rv = profile->Lock(nullptr, aResult); |
2524 | 0 | if (NS_SUCCEEDED(rv)) { |
2525 | 0 | if (aProfileName) |
2526 | | #ifdef MOZ_DEV_EDITION |
2527 | | aProfileName->AssignLiteral("dev-edition-default"); |
2528 | | #else |
2529 | 0 | aProfileName->AssignLiteral("default"); |
2530 | 0 | #endif |
2531 | 0 | return NS_OK; |
2532 | 0 | } |
2533 | 0 | } |
2534 | 0 | } |
2535 | 0 |
|
2536 | 0 | bool useDefault = true; |
2537 | 0 | if (count > 1) { |
2538 | 0 | aProfileSvc->GetStartWithLastProfile(&useDefault); |
2539 | 0 | } |
2540 | 0 |
|
2541 | 0 | if (useDefault) { |
2542 | 0 | nsCOMPtr<nsIToolkitProfile> profile; |
2543 | 0 | // GetSelectedProfile will auto-select the only profile if there's just one |
2544 | 0 | aProfileSvc->GetSelectedProfile(getter_AddRefs(profile)); |
2545 | 0 | if (profile) { |
2546 | 0 | // If we're resetting a profile, create a new one and use it to startup. |
2547 | 0 | if (gDoProfileReset) { |
2548 | 0 | { |
2549 | 0 | // Check that the source profile is not in use by temporarily acquiring its lock. |
2550 | 0 | nsIProfileLock* tempProfileLock; |
2551 | 0 | nsCOMPtr<nsIProfileUnlocker> unlocker; |
2552 | 0 | rv = profile->Lock(getter_AddRefs(unlocker), &tempProfileLock); |
2553 | 0 | if (NS_FAILED(rv)) |
2554 | 0 | return ProfileLockedDialog(profile, unlocker, aNative, &tempProfileLock); |
2555 | 0 | } |
2556 | 0 | |
2557 | 0 | nsresult gotName = profile->GetName(gResetOldProfileName); |
2558 | 0 | if (NS_SUCCEEDED(gotName)) { |
2559 | 0 | nsCOMPtr<nsIToolkitProfile> newProfile; |
2560 | 0 | rv = CreateResetProfile(aProfileSvc, gResetOldProfileName, getter_AddRefs(newProfile)); |
2561 | 0 | if (NS_FAILED(rv)) { |
2562 | 0 | NS_WARNING("Failed to create a profile to reset to."); |
2563 | 0 | gDoProfileReset = false; |
2564 | 0 | } |
2565 | 0 | else { |
2566 | 0 | profile = newProfile; |
2567 | 0 | } |
2568 | 0 | } |
2569 | 0 | else { |
2570 | 0 | NS_WARNING("Failed to get the name of the profile we're resetting, so aborting reset."); |
2571 | 0 | gResetOldProfileName.Truncate(0); |
2572 | 0 | gDoProfileReset = false; |
2573 | 0 | } |
2574 | 0 | } |
2575 | 0 |
|
2576 | 0 | // If you close Firefox and very quickly reopen it, the old Firefox may |
2577 | 0 | // still be closing down. Rather than immediately showing the |
2578 | 0 | // "Firefox is running but is not responding" message, we spend a few |
2579 | 0 | // seconds retrying first. |
2580 | 0 |
|
2581 | 0 | static const int kLockRetrySeconds = 5; |
2582 | 0 | static const int kLockRetrySleepMS = 100; |
2583 | 0 |
|
2584 | 0 | nsCOMPtr<nsIProfileUnlocker> unlocker; |
2585 | 0 | const TimeStamp start = TimeStamp::Now(); |
2586 | 0 | do { |
2587 | 0 | rv = profile->Lock(getter_AddRefs(unlocker), aResult); |
2588 | 0 | if (NS_SUCCEEDED(rv)) { |
2589 | 0 | StartupTimeline::Record(StartupTimeline::AFTER_PROFILE_LOCKED); |
2590 | 0 | // Try to grab the profile name. |
2591 | 0 | if (aProfileName) { |
2592 | 0 | rv = profile->GetName(*aProfileName); |
2593 | 0 | if (NS_FAILED(rv)) |
2594 | 0 | aProfileName->Truncate(0); |
2595 | 0 | } |
2596 | 0 | return NS_OK; |
2597 | 0 | } |
2598 | 0 | PR_Sleep(kLockRetrySleepMS); |
2599 | 0 | } while (TimeStamp::Now() - start < TimeDuration::FromSeconds(kLockRetrySeconds)); |
2600 | 0 |
|
2601 | 0 | return ProfileLockedDialog(profile, unlocker, aNative, aResult); |
2602 | 0 | } |
2603 | 0 | } |
2604 | 0 | |
2605 | 0 | return ShowProfileManager(aProfileSvc, aNative); |
2606 | 0 | } |
2607 | | |
2608 | | /** |
2609 | | * Checks the compatibility.ini file to see if we have updated our application |
2610 | | * or otherwise invalidated our caches. If the application has been updated, |
2611 | | * we return false; otherwise, we return true. We also write the status |
2612 | | * of the caches (valid/invalid) into the return param aCachesOK. The aCachesOK |
2613 | | * is always invalid if the application has been updated. |
2614 | | */ |
2615 | | static bool |
2616 | | CheckCompatibility(nsIFile* aProfileDir, const nsCString& aVersion, |
2617 | | const nsCString& aOSABI, nsIFile* aXULRunnerDir, |
2618 | | nsIFile* aAppDir, nsIFile* aFlagFile, |
2619 | | bool* aCachesOK) |
2620 | 0 | { |
2621 | 0 | *aCachesOK = false; |
2622 | 0 | nsCOMPtr<nsIFile> file; |
2623 | 0 | aProfileDir->Clone(getter_AddRefs(file)); |
2624 | 0 | if (!file) |
2625 | 0 | return false; |
2626 | 0 | file->AppendNative(FILE_COMPATIBILITY_INFO); |
2627 | 0 |
|
2628 | 0 | nsINIParser parser; |
2629 | 0 | nsresult rv = parser.Init(file); |
2630 | 0 | if (NS_FAILED(rv)) |
2631 | 0 | return false; |
2632 | 0 | |
2633 | 0 | nsAutoCString buf; |
2634 | 0 | rv = parser.GetString("Compatibility", "LastVersion", buf); |
2635 | 0 | if (NS_FAILED(rv) || !aVersion.Equals(buf)) |
2636 | 0 | return false; |
2637 | 0 | |
2638 | 0 | rv = parser.GetString("Compatibility", "LastOSABI", buf); |
2639 | 0 | if (NS_FAILED(rv) || !aOSABI.Equals(buf)) |
2640 | 0 | return false; |
2641 | 0 | |
2642 | 0 | rv = parser.GetString("Compatibility", "LastPlatformDir", buf); |
2643 | 0 | if (NS_FAILED(rv)) |
2644 | 0 | return false; |
2645 | 0 | |
2646 | 0 | nsCOMPtr<nsIFile> lf; |
2647 | 0 | rv = NS_NewNativeLocalFile(EmptyCString(), false, |
2648 | 0 | getter_AddRefs(lf)); |
2649 | 0 | if (NS_FAILED(rv)) |
2650 | 0 | return false; |
2651 | 0 | |
2652 | 0 | rv = lf->SetPersistentDescriptor(buf); |
2653 | 0 | if (NS_FAILED(rv)) |
2654 | 0 | return false; |
2655 | 0 | |
2656 | 0 | bool eq; |
2657 | 0 | rv = lf->Equals(aXULRunnerDir, &eq); |
2658 | 0 | if (NS_FAILED(rv) || !eq) |
2659 | 0 | return false; |
2660 | 0 | |
2661 | 0 | if (aAppDir) { |
2662 | 0 | rv = parser.GetString("Compatibility", "LastAppDir", buf); |
2663 | 0 | if (NS_FAILED(rv)) |
2664 | 0 | return false; |
2665 | 0 | |
2666 | 0 | rv = NS_NewNativeLocalFile(EmptyCString(), false, |
2667 | 0 | getter_AddRefs(lf)); |
2668 | 0 | if (NS_FAILED(rv)) |
2669 | 0 | return false; |
2670 | 0 | |
2671 | 0 | rv = lf->SetPersistentDescriptor(buf); |
2672 | 0 | if (NS_FAILED(rv)) |
2673 | 0 | return false; |
2674 | 0 | |
2675 | 0 | rv = lf->Equals(aAppDir, &eq); |
2676 | 0 | if (NS_FAILED(rv) || !eq) |
2677 | 0 | return false; |
2678 | 0 | } |
2679 | 0 | |
2680 | 0 | // If we see this flag, caches are invalid. |
2681 | 0 | rv = parser.GetString("Compatibility", "InvalidateCaches", buf); |
2682 | 0 | *aCachesOK = (NS_FAILED(rv) || !buf.EqualsLiteral("1")); |
2683 | 0 |
|
2684 | 0 | bool purgeCaches = false; |
2685 | 0 | if (aFlagFile) { |
2686 | 0 | aFlagFile->Exists(&purgeCaches); |
2687 | 0 | } |
2688 | 0 |
|
2689 | 0 | *aCachesOK = !purgeCaches && *aCachesOK; |
2690 | 0 | return true; |
2691 | 0 | } |
2692 | | |
2693 | | static void BuildVersion(nsCString &aBuf) |
2694 | 0 | { |
2695 | 0 | aBuf.Assign(gAppData->version); |
2696 | 0 | aBuf.Append('_'); |
2697 | 0 | aBuf.Append(gAppData->buildID); |
2698 | 0 | aBuf.Append('/'); |
2699 | 0 | aBuf.Append(gToolkitBuildID); |
2700 | 0 | } |
2701 | | |
2702 | | static void |
2703 | | WriteVersion(nsIFile* aProfileDir, const nsCString& aVersion, |
2704 | | const nsCString& aOSABI, nsIFile* aXULRunnerDir, |
2705 | | nsIFile* aAppDir, bool invalidateCache) |
2706 | 0 | { |
2707 | 0 | nsCOMPtr<nsIFile> file; |
2708 | 0 | aProfileDir->Clone(getter_AddRefs(file)); |
2709 | 0 | if (!file) |
2710 | 0 | return; |
2711 | 0 | file->AppendNative(FILE_COMPATIBILITY_INFO); |
2712 | 0 |
|
2713 | 0 | nsAutoCString platformDir; |
2714 | 0 | Unused << aXULRunnerDir->GetPersistentDescriptor(platformDir); |
2715 | 0 |
|
2716 | 0 | nsAutoCString appDir; |
2717 | 0 | if (aAppDir) |
2718 | 0 | Unused << aAppDir->GetPersistentDescriptor(appDir); |
2719 | 0 |
|
2720 | 0 | PRFileDesc *fd; |
2721 | 0 | nsresult rv = |
2722 | 0 | file->OpenNSPRFileDesc(PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, 0600, &fd); |
2723 | 0 | if (NS_FAILED(rv)) { |
2724 | 0 | NS_ERROR("could not create output stream"); |
2725 | 0 | return; |
2726 | 0 | } |
2727 | 0 |
|
2728 | 0 | static const char kHeader[] = "[Compatibility]" NS_LINEBREAK |
2729 | 0 | "LastVersion="; |
2730 | 0 |
|
2731 | 0 | PR_Write(fd, kHeader, sizeof(kHeader) - 1); |
2732 | 0 | PR_Write(fd, aVersion.get(), aVersion.Length()); |
2733 | 0 |
|
2734 | 0 | static const char kOSABIHeader[] = NS_LINEBREAK "LastOSABI="; |
2735 | 0 | PR_Write(fd, kOSABIHeader, sizeof(kOSABIHeader) - 1); |
2736 | 0 | PR_Write(fd, aOSABI.get(), aOSABI.Length()); |
2737 | 0 |
|
2738 | 0 | static const char kPlatformDirHeader[] = NS_LINEBREAK "LastPlatformDir="; |
2739 | 0 |
|
2740 | 0 | PR_Write(fd, kPlatformDirHeader, sizeof(kPlatformDirHeader) - 1); |
2741 | 0 | PR_Write(fd, platformDir.get(), platformDir.Length()); |
2742 | 0 |
|
2743 | 0 | static const char kAppDirHeader[] = NS_LINEBREAK "LastAppDir="; |
2744 | 0 | if (aAppDir) { |
2745 | 0 | PR_Write(fd, kAppDirHeader, sizeof(kAppDirHeader) - 1); |
2746 | 0 | PR_Write(fd, appDir.get(), appDir.Length()); |
2747 | 0 | } |
2748 | 0 |
|
2749 | 0 | static const char kInvalidationHeader[] = NS_LINEBREAK "InvalidateCaches=1"; |
2750 | 0 | if (invalidateCache) |
2751 | 0 | PR_Write(fd, kInvalidationHeader, sizeof(kInvalidationHeader) - 1); |
2752 | 0 |
|
2753 | 0 | static const char kNL[] = NS_LINEBREAK; |
2754 | 0 | PR_Write(fd, kNL, sizeof(kNL) - 1); |
2755 | 0 |
|
2756 | 0 | PR_Close(fd); |
2757 | 0 | } |
2758 | | |
2759 | | /** |
2760 | | * Returns true if the startup cache file was successfully removed. |
2761 | | * Returns false if file->Clone fails at any point (OOM) or if unable |
2762 | | * to remove the startup cache file. Note in particular the return value |
2763 | | * is unaffected by a failure to remove extensions.ini |
2764 | | */ |
2765 | | static bool |
2766 | | RemoveComponentRegistries(nsIFile* aProfileDir, nsIFile* aLocalProfileDir, |
2767 | | bool aRemoveEMFiles) |
2768 | 0 | { |
2769 | 0 | nsCOMPtr<nsIFile> file; |
2770 | 0 | aProfileDir->Clone(getter_AddRefs(file)); |
2771 | 0 | if (!file) |
2772 | 0 | return false; |
2773 | 0 | |
2774 | 0 | if (aRemoveEMFiles) { |
2775 | 0 | file->SetNativeLeafName(NS_LITERAL_CSTRING("extensions.ini")); |
2776 | 0 | file->Remove(false); |
2777 | 0 | } |
2778 | 0 |
|
2779 | 0 | aLocalProfileDir->Clone(getter_AddRefs(file)); |
2780 | 0 | if (!file) |
2781 | 0 | return false; |
2782 | 0 | |
2783 | 0 | #if defined(XP_UNIX) || defined(XP_BEOS) |
2784 | 0 | #define PLATFORM_FASL_SUFFIX ".mfasl" |
2785 | | #elif defined(XP_WIN) |
2786 | | #define PLATFORM_FASL_SUFFIX ".mfl" |
2787 | | #endif |
2788 | | |
2789 | 0 | file->AppendNative(NS_LITERAL_CSTRING("XUL" PLATFORM_FASL_SUFFIX)); |
2790 | 0 | file->Remove(false); |
2791 | 0 |
|
2792 | 0 | file->SetNativeLeafName(NS_LITERAL_CSTRING("XPC" PLATFORM_FASL_SUFFIX)); |
2793 | 0 | file->Remove(false); |
2794 | 0 |
|
2795 | 0 | file->SetNativeLeafName(NS_LITERAL_CSTRING("startupCache")); |
2796 | 0 | nsresult rv = file->Remove(true); |
2797 | 0 | return NS_SUCCEEDED(rv) || rv == NS_ERROR_FILE_TARGET_DOES_NOT_EXIST; |
2798 | 0 | } |
2799 | | |
2800 | | // To support application initiated restart via nsIAppStartup.quit, we |
2801 | | // need to save various environment variables, and then restore them |
2802 | | // before re-launching the application. |
2803 | | |
2804 | | static struct SavedVar { |
2805 | | const char *name; |
2806 | | char *value; |
2807 | | } gSavedVars[] = { |
2808 | | {"XUL_APP_FILE", nullptr} |
2809 | | }; |
2810 | | |
2811 | | static void SaveStateForAppInitiatedRestart() |
2812 | 0 | { |
2813 | 0 | for (auto & savedVar : gSavedVars) { |
2814 | 0 | const char *s = PR_GetEnv(savedVar.name); |
2815 | 0 | if (s) |
2816 | 0 | savedVar.value = Smprintf("%s=%s", savedVar.name, s).release(); |
2817 | 0 | } |
2818 | 0 | } |
2819 | | |
2820 | | static void RestoreStateForAppInitiatedRestart() |
2821 | 0 | { |
2822 | 0 | for (auto & savedVar : gSavedVars) { |
2823 | 0 | if (savedVar.value) |
2824 | 0 | PR_SetEnv(savedVar.value); |
2825 | 0 | } |
2826 | 0 | } |
2827 | | |
2828 | | // When we first initialize the crash reporter we don't have a profile, |
2829 | | // so we set the minidump path to $TEMP. Once we have a profile, |
2830 | | // we set it to $PROFILE/minidumps, creating the directory |
2831 | | // if needed. |
2832 | | static void MakeOrSetMinidumpPath(nsIFile* profD) |
2833 | 0 | { |
2834 | 0 | nsCOMPtr<nsIFile> dumpD; |
2835 | 0 | profD->Clone(getter_AddRefs(dumpD)); |
2836 | 0 |
|
2837 | 0 | if (dumpD) { |
2838 | 0 | bool fileExists; |
2839 | 0 | //XXX: do some more error checking here |
2840 | 0 | dumpD->Append(NS_LITERAL_STRING("minidumps")); |
2841 | 0 | dumpD->Exists(&fileExists); |
2842 | 0 | if (!fileExists) { |
2843 | 0 | nsresult rv = dumpD->Create(nsIFile::DIRECTORY_TYPE, 0700); |
2844 | 0 | NS_ENSURE_SUCCESS_VOID(rv); |
2845 | 0 | } |
2846 | 0 |
|
2847 | 0 | nsAutoString pathStr; |
2848 | 0 | if (NS_SUCCEEDED(dumpD->GetPath(pathStr))) |
2849 | 0 | CrashReporter::SetMinidumpPath(pathStr); |
2850 | 0 | } |
2851 | 0 | } |
2852 | | |
2853 | | const XREAppData* gAppData = nullptr; |
2854 | | |
2855 | | #ifdef MOZ_WIDGET_GTK |
2856 | | static void MOZ_gdk_display_close(GdkDisplay *display) |
2857 | 0 | { |
2858 | | #if CLEANUP_MEMORY |
2859 | | // XXX wallpaper for bug 417163: don't close the Display if we're using the |
2860 | | // Qt theme because we crash (in Qt code) when using jemalloc. |
2861 | | bool skip_display_close = false; |
2862 | | GtkSettings* settings = |
2863 | | gtk_settings_get_for_screen(gdk_display_get_default_screen(display)); |
2864 | | gchar *theme_name; |
2865 | | g_object_get(settings, "gtk-theme-name", &theme_name, nullptr); |
2866 | | if (theme_name) { |
2867 | | skip_display_close = strcmp(theme_name, "Qt") == 0; |
2868 | | if (skip_display_close) |
2869 | | NS_WARNING("wallpaper bug 417163 for Qt theme"); |
2870 | | g_free(theme_name); |
2871 | | } |
2872 | | |
2873 | | #ifdef MOZ_WIDGET_GTK |
2874 | | // A workaround for https://bugzilla.gnome.org/show_bug.cgi?id=703257 |
2875 | | if (gtk_check_version(3,9,8) != NULL) |
2876 | | skip_display_close = true; |
2877 | | #endif |
2878 | | |
2879 | | // Get a (new) Pango context that holds a reference to the fontmap that |
2880 | | // GTK has been using. gdk_pango_context_get() must be called while GTK |
2881 | | // has a default display. |
2882 | | PangoContext *pangoContext = gdk_pango_context_get(); |
2883 | | |
2884 | | bool buggyCairoShutdown = cairo_version() < CAIRO_VERSION_ENCODE(1, 4, 0); |
2885 | | |
2886 | | if (!buggyCairoShutdown) { |
2887 | | // We should shut down GDK before we shut down libraries it depends on |
2888 | | // like Pango and cairo. But if cairo shutdown is buggy, we should |
2889 | | // shut down cairo first otherwise it may crash because of dangling |
2890 | | // references to Display objects (see bug 469831). |
2891 | | if (!skip_display_close) |
2892 | | gdk_display_close(display); |
2893 | | } |
2894 | | |
2895 | | // Clean up PangoCairo's default fontmap. |
2896 | | // This pango_fc_font_map_shutdown call (and the associated code to |
2897 | | // get the font map) really shouldn't be needed anymore, except that |
2898 | | // it's needed to avoid having cairo_debug_reset_static_data fatally |
2899 | | // assert if we've leaked other things that hold on to the fontmap, |
2900 | | // which is something that currently happens in mochitest-plugins. |
2901 | | // Even if it didn't happen in mochitest-plugins, we probably want to |
2902 | | // avoid the crash-on-leak problem since it makes it harder to use |
2903 | | // many of our leak tools to debug leaks. |
2904 | | |
2905 | | // This doesn't take a reference. |
2906 | | PangoFontMap *fontmap = pango_context_get_font_map(pangoContext); |
2907 | | // Do some shutdown of the fontmap, which releases the fonts, clearing a |
2908 | | // bunch of circular references from the fontmap through the fonts back to |
2909 | | // itself. The shutdown that this does is much less than what's done by |
2910 | | // the fontmap's finalize, though. |
2911 | | if (PANGO_IS_FC_FONT_MAP(fontmap)) |
2912 | | pango_fc_font_map_shutdown(PANGO_FC_FONT_MAP(fontmap)); |
2913 | | g_object_unref(pangoContext); |
2914 | | |
2915 | | // Tell PangoCairo to release its default fontmap. |
2916 | | pango_cairo_font_map_set_default(nullptr); |
2917 | | |
2918 | | // cairo_debug_reset_static_data() is prototyped through cairo.h included |
2919 | | // by gtk.h. |
2920 | | #ifdef cairo_debug_reset_static_data |
2921 | | #error "Looks like we're including Mozilla's cairo instead of system cairo" |
2922 | | #endif |
2923 | | cairo_debug_reset_static_data(); |
2924 | | // FIXME: Do we need to call this in non-GTK2 cases as well? |
2925 | | FcFini(); |
2926 | | |
2927 | | if (buggyCairoShutdown) { |
2928 | | if (!skip_display_close) |
2929 | | gdk_display_close(display); |
2930 | | } |
2931 | | #else // not CLEANUP_MEMORY |
2932 | | // Don't do anything to avoid running into driver bugs under XCloseDisplay(). |
2933 | 0 | // See bug 973192. |
2934 | 0 | (void) display; |
2935 | 0 | #endif |
2936 | 0 | } |
2937 | | #endif |
2938 | | |
2939 | | /** |
2940 | | * NSPR will search for the "nspr_use_zone_allocator" symbol throughout |
2941 | | * the process and use it to determine whether the application defines its own |
2942 | | * memory allocator or not. |
2943 | | * |
2944 | | * Since most applications (e.g. Firefox and Thunderbird) don't use any special |
2945 | | * allocators and therefore don't define this symbol, NSPR must search the |
2946 | | * entire process, which reduces startup performance. |
2947 | | * |
2948 | | * By defining the symbol here, we can avoid the wasted lookup and hopefully |
2949 | | * improve startup performance. |
2950 | | */ |
2951 | | NS_VISIBILITY_DEFAULT PRBool nspr_use_zone_allocator = PR_FALSE; |
2952 | | |
2953 | | #ifdef CAIRO_HAS_DWRITE_FONT |
2954 | | |
2955 | | #include <dwrite.h> |
2956 | | |
2957 | | #ifdef DEBUG_DWRITE_STARTUP |
2958 | | |
2959 | | #define LOGREGISTRY(msg) LogRegistryEvent(msg) |
2960 | | |
2961 | | // for use when monitoring process |
2962 | | static void LogRegistryEvent(const wchar_t *msg) |
2963 | | { |
2964 | | HKEY dummyKey; |
2965 | | HRESULT hr; |
2966 | | wchar_t buf[512]; |
2967 | | |
2968 | | wsprintf(buf, L" log %s", msg); |
2969 | | hr = RegOpenKeyEx(HKEY_LOCAL_MACHINE, buf, 0, KEY_READ, &dummyKey); |
2970 | | if (SUCCEEDED(hr)) { |
2971 | | RegCloseKey(dummyKey); |
2972 | | } |
2973 | | } |
2974 | | #else |
2975 | | |
2976 | | #define LOGREGISTRY(msg) |
2977 | | |
2978 | | #endif |
2979 | | |
2980 | | static DWORD WINAPI InitDwriteBG(LPVOID lpdwThreadParam) |
2981 | | { |
2982 | | SetThreadPriority(GetCurrentThread(), THREAD_MODE_BACKGROUND_BEGIN); |
2983 | | LOGREGISTRY(L"loading dwrite.dll"); |
2984 | | HMODULE dwdll = LoadLibraryW(L"dwrite.dll"); |
2985 | | if (dwdll) { |
2986 | | decltype(DWriteCreateFactory)* createDWriteFactory = (decltype(DWriteCreateFactory)*) |
2987 | | GetProcAddress(dwdll, "DWriteCreateFactory"); |
2988 | | if (createDWriteFactory) { |
2989 | | LOGREGISTRY(L"creating dwrite factory"); |
2990 | | IDWriteFactory *factory; |
2991 | | HRESULT hr = createDWriteFactory( |
2992 | | DWRITE_FACTORY_TYPE_SHARED, |
2993 | | __uuidof(IDWriteFactory), |
2994 | | reinterpret_cast<IUnknown**>(&factory)); |
2995 | | if (SUCCEEDED(hr)) { |
2996 | | LOGREGISTRY(L"dwrite factory done"); |
2997 | | factory->Release(); |
2998 | | LOGREGISTRY(L"freed factory"); |
2999 | | } else { |
3000 | | LOGREGISTRY(L"failed to create factory"); |
3001 | | } |
3002 | | } |
3003 | | } |
3004 | | SetThreadPriority(GetCurrentThread(), THREAD_MODE_BACKGROUND_END); |
3005 | | return 0; |
3006 | | } |
3007 | | #endif |
3008 | | |
3009 | | #ifdef USE_GLX_TEST |
3010 | | bool fire_glxtest_process(); |
3011 | | #endif |
3012 | | |
3013 | | #include "GeckoProfiler.h" |
3014 | | |
3015 | | // Encapsulates startup and shutdown state for XRE_main |
3016 | | class XREMain |
3017 | | { |
3018 | | public: |
3019 | | XREMain() : |
3020 | | mStartOffline(false) |
3021 | | , mShuttingDown(false) |
3022 | | #ifdef MOZ_ENABLE_XREMOTE |
3023 | | , mDisableRemote(false) |
3024 | | #endif |
3025 | | #if defined(MOZ_WIDGET_GTK) |
3026 | | , mGdkDisplay(nullptr) |
3027 | | #endif |
3028 | 3 | {}; |
3029 | | |
3030 | 0 | ~XREMain() { |
3031 | 0 | mScopedXPCOM = nullptr; |
3032 | 0 | mAppData = nullptr; |
3033 | 0 | } |
3034 | | |
3035 | | int XRE_main(int argc, char* argv[], const BootstrapConfig& aConfig); |
3036 | | int XRE_mainInit(bool* aExitFlag); |
3037 | | int XRE_mainStartup(bool* aExitFlag); |
3038 | | nsresult XRE_mainRun(); |
3039 | | |
3040 | | Result<bool, nsresult> CheckLastStartupWasCrash(); |
3041 | | |
3042 | | nsCOMPtr<nsINativeAppSupport> mNativeApp; |
3043 | | nsCOMPtr<nsIToolkitProfileService> mProfileSvc; |
3044 | | nsCOMPtr<nsIFile> mProfD; |
3045 | | nsCOMPtr<nsIFile> mProfLD; |
3046 | | nsCOMPtr<nsIProfileLock> mProfileLock; |
3047 | | #ifdef MOZ_ENABLE_XREMOTE |
3048 | | nsCOMPtr<nsIRemoteService> mRemoteService; |
3049 | | nsProfileLock mRemoteLock; |
3050 | | nsCOMPtr<nsIFile> mRemoteLockDir; |
3051 | | #endif |
3052 | | |
3053 | | UniquePtr<ScopedXPCOMStartup> mScopedXPCOM; |
3054 | | UniquePtr<XREAppData> mAppData; |
3055 | | |
3056 | | nsXREDirProvider mDirProvider; |
3057 | | nsAutoCString mProfileName; |
3058 | | nsAutoCString mDesktopStartupID; |
3059 | | |
3060 | | bool mStartOffline; |
3061 | | bool mShuttingDown; |
3062 | | #ifdef MOZ_ENABLE_XREMOTE |
3063 | | bool mDisableRemote; |
3064 | | #endif |
3065 | | |
3066 | | #if defined(MOZ_WIDGET_GTK) |
3067 | | GdkDisplay* mGdkDisplay; |
3068 | | #endif |
3069 | | }; |
3070 | | |
3071 | | #if defined(XP_UNIX) && !defined(ANDROID) |
3072 | | static SmprintfPointer |
3073 | | FormatUid(uid_t aId) |
3074 | 0 | { |
3075 | 0 | if (const auto pw = getpwuid(aId)) { |
3076 | 0 | return mozilla::Smprintf("%s", pw->pw_name); |
3077 | 0 | } |
3078 | 0 | return mozilla::Smprintf("uid %d", static_cast<int>(aId)); |
3079 | 0 | } |
3080 | | |
3081 | | // Bug 1323302: refuse to run under sudo or similar. |
3082 | | static bool |
3083 | | CheckForUserMismatch() |
3084 | 3 | { |
3085 | 3 | static char const * const kVars[] = { |
3086 | 3 | "HOME", |
3087 | 3 | #ifdef MOZ_WIDGET_GTK |
3088 | 3 | "XDG_RUNTIME_DIR", |
3089 | 3 | #endif |
3090 | 3 | #ifdef MOZ_X11 |
3091 | 3 | "XAUTHORITY", |
3092 | 3 | #endif |
3093 | 3 | }; |
3094 | 3 | |
3095 | 3 | const uid_t euid = geteuid(); |
3096 | 3 | if (euid != 0) { |
3097 | 0 | // On Linux it's possible to have superuser capabilities with a |
3098 | 0 | // nonzero uid, but anyone who knows enough to make that happen |
3099 | 0 | // probably knows enough to debug the resulting problems. |
3100 | 0 | // Otherwise, a non-root user can't cause the problems we're |
3101 | 0 | // concerned about. |
3102 | 0 | return false; |
3103 | 0 | } |
3104 | 3 | |
3105 | 9 | for (const auto var : kVars) { |
3106 | 9 | if (const auto path = PR_GetEnv(var)) { |
3107 | 3 | struct stat st; |
3108 | 3 | if (stat(path, &st) == 0) { |
3109 | 3 | if (st.st_uid != euid) { |
3110 | 0 | const auto owner = FormatUid(st.st_uid); |
3111 | 0 | Output(true, "Running " MOZ_APP_DISPLAYNAME " as root in a regular" |
3112 | 0 | " user's session is not supported. ($%s is %s which is" |
3113 | 0 | " owned by %s.)\n", |
3114 | 0 | var, path, owner.get()); |
3115 | 0 | return true; |
3116 | 0 | } |
3117 | 3 | } |
3118 | 3 | } |
3119 | 9 | } |
3120 | 3 | return false; |
3121 | 3 | } |
3122 | | #else // !XP_UNIX || ANDROID |
3123 | | static bool |
3124 | | CheckForUserMismatch() |
3125 | | { |
3126 | | return false; |
3127 | | } |
3128 | | #endif |
3129 | | |
3130 | | static void |
3131 | | IncreaseDescriptorLimits() |
3132 | 3 | { |
3133 | 3 | #ifdef XP_UNIX |
3134 | 3 | // Increase the fd limit to accomodate IPC resources like shared memory. |
3135 | 3 | static const rlim_t kFDs = 4096; |
3136 | 3 | struct rlimit rlim; |
3137 | 3 | |
3138 | 3 | if (getrlimit(RLIMIT_NOFILE, &rlim) != 0) { |
3139 | 0 | Output(false, "getrlimit: %s\n", strerror(errno)); |
3140 | 0 | return; |
3141 | 0 | } |
3142 | 3 | // Don't decrease the limit if it's already high enough, but don't |
3143 | 3 | // try to go over the hard limit. (RLIM_INFINITY isn't required to |
3144 | 3 | // be the numerically largest rlim_t, so don't assume that.) |
3145 | 3 | if (rlim.rlim_cur != RLIM_INFINITY && rlim.rlim_cur < kFDs && |
3146 | 3 | rlim.rlim_cur < rlim.rlim_max) { |
3147 | 0 | if (rlim.rlim_max != RLIM_INFINITY && rlim.rlim_max < kFDs) { |
3148 | 0 | rlim.rlim_cur = rlim.rlim_max; |
3149 | 0 | } else { |
3150 | 0 | rlim.rlim_cur = kFDs; |
3151 | 0 | } |
3152 | 0 | if (setrlimit(RLIMIT_NOFILE, &rlim) != 0) { |
3153 | 0 | Output(false, "setrlimit: %s\n", strerror(errno)); |
3154 | 0 | } |
3155 | 0 | } |
3156 | 3 | #endif |
3157 | 3 | } |
3158 | | |
3159 | | /* |
3160 | | * XRE_mainInit - Initial setup and command line parameter processing. |
3161 | | * Main() will exit early if either return value != 0 or if aExitFlag is |
3162 | | * true. |
3163 | | */ |
3164 | | int |
3165 | | XREMain::XRE_mainInit(bool* aExitFlag) |
3166 | 3 | { |
3167 | 3 | if (!aExitFlag) |
3168 | 0 | return 1; |
3169 | 3 | *aExitFlag = false; |
3170 | 3 | |
3171 | 3 | atexit(UnexpectedExit); |
3172 | 3 | auto expectedShutdown = mozilla::MakeScopeExit([&] { |
3173 | 3 | MozExpectedExit(); |
3174 | 3 | }); |
3175 | 3 | |
3176 | 3 | StartupTimeline::Record(StartupTimeline::MAIN); |
3177 | 3 | |
3178 | 3 | if (CheckForUserMismatch()) { |
3179 | 0 | return 1; |
3180 | 0 | } |
3181 | 3 | |
3182 | 3 | if (PR_GetEnv("MOZ_CHAOSMODE")) { |
3183 | 0 | ChaosFeature feature = ChaosFeature::Any; |
3184 | 0 | long featureInt = strtol(PR_GetEnv("MOZ_CHAOSMODE"), nullptr, 16); |
3185 | 0 | if (featureInt) { |
3186 | 0 | // NOTE: MOZ_CHAOSMODE=0 or a non-hex value maps to Any feature. |
3187 | 0 | feature = static_cast<ChaosFeature>(featureInt); |
3188 | 0 | } |
3189 | 0 | ChaosMode::SetChaosFeature(feature); |
3190 | 0 | } |
3191 | 3 | |
3192 | | #ifdef MOZ_ASAN_REPORTER |
3193 | | // In ASan Reporter builds, we enable certain chaos features by default unless |
3194 | | // the user explicitly requests a particular set of features. |
3195 | | if (!PR_GetEnv("MOZ_CHAOSMODE")) { |
3196 | | ChaosMode::SetChaosFeature(static_cast<ChaosFeature>( |
3197 | | ChaosFeature::ThreadScheduling |
3198 | | | ChaosFeature::NetworkScheduling |
3199 | | | ChaosFeature::TimerScheduling |
3200 | | | ChaosFeature::TaskDispatching |
3201 | | | ChaosFeature::TaskRunning)); |
3202 | | } |
3203 | | #endif |
3204 | | |
3205 | 3 | if (ChaosMode::isActive(ChaosFeature::Any)) { |
3206 | 0 | printf_stderr("*** You are running in chaos test mode. See ChaosMode.h. ***\n"); |
3207 | 0 | } |
3208 | 3 | |
3209 | 3 | if (CheckArg("headless") || CheckArgExists("screenshot")) { |
3210 | 0 | PR_SetEnv("MOZ_HEADLESS=1"); |
3211 | 0 | } |
3212 | 3 | |
3213 | 3 | if (gfxPlatform::IsHeadless()) { |
3214 | 0 | #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) || defined(XP_MACOSX) |
3215 | 0 | printf_stderr("*** You are running in headless mode.\n"); |
3216 | | #else |
3217 | | Output(true, "Error: headless mode is not currently supported on this platform.\n"); |
3218 | | return 1; |
3219 | | #endif |
3220 | |
|
3221 | | #ifdef XP_MACOSX |
3222 | | // To avoid taking focus when running in headless mode immediately |
3223 | | // transition Firefox to a background application. |
3224 | | ProcessSerialNumber psn = { 0, kCurrentProcess }; |
3225 | | OSStatus transformStatus = TransformProcessType(&psn, kProcessTransformToBackgroundApplication); |
3226 | | if (transformStatus != noErr) { |
3227 | | NS_ERROR("Failed to make process a background application."); |
3228 | | return 1; |
3229 | | } |
3230 | | #endif |
3231 | |
|
3232 | 0 | } |
3233 | 3 | |
3234 | 3 | nsresult rv; |
3235 | 3 | ArgResult ar; |
3236 | 3 | |
3237 | | #ifdef DEBUG |
3238 | | if (PR_GetEnv("XRE_MAIN_BREAK")) |
3239 | | NS_BREAK(); |
3240 | | #endif |
3241 | | |
3242 | 3 | IncreaseDescriptorLimits(); |
3243 | 3 | |
3244 | 3 | #ifdef USE_GLX_TEST |
3245 | 3 | // bug 639842 - it's very important to fire this process BEFORE we set up |
3246 | 3 | // error handling. indeed, this process is expected to be crashy, and we |
3247 | 3 | // don't want the user to see its crashes. That's the whole reason for |
3248 | 3 | // doing this in a separate process. |
3249 | 3 | // |
3250 | 3 | // This call will cause a fork and the fork will terminate itself separately |
3251 | 3 | // from the usual shutdown sequence |
3252 | 3 | fire_glxtest_process(); |
3253 | 3 | #endif |
3254 | 3 | |
3255 | 3 | SetupErrorHandling(gArgv[0]); |
3256 | 3 | |
3257 | | #ifdef CAIRO_HAS_DWRITE_FONT |
3258 | | { |
3259 | | // Bug 602792 - when DWriteCreateFactory is called the dwrite client dll |
3260 | | // starts the FntCache service if it isn't already running (it's set |
3261 | | // to manual startup by default in Windows 7 RTM). Subsequent DirectWrite |
3262 | | // calls cause the IDWriteFactory object to communicate with the FntCache |
3263 | | // service with a timeout; if there's no response after the timeout, the |
3264 | | // DirectWrite client library will assume the service isn't around and do |
3265 | | // manual font file I/O on _all_ system fonts. To avoid this, load the |
3266 | | // dwrite library and create a factory as early as possible so that the |
3267 | | // FntCache service is ready by the time it's needed. |
3268 | | |
3269 | | CreateThread(nullptr, 0, &InitDwriteBG, nullptr, 0, nullptr); |
3270 | | } |
3271 | | #endif |
3272 | | |
3273 | 3 | #ifdef XP_UNIX |
3274 | 3 | const char *home = PR_GetEnv("HOME"); |
3275 | 3 | if (!home || !*home) { |
3276 | 0 | struct passwd *pw = getpwuid(geteuid()); |
3277 | 0 | if (!pw || !pw->pw_dir) { |
3278 | 0 | Output(true, "Could not determine HOME directory"); |
3279 | 0 | return 1; |
3280 | 0 | } |
3281 | 0 | SaveWordToEnv("HOME", nsDependentCString(pw->pw_dir)); |
3282 | 0 | } |
3283 | 3 | #endif |
3284 | 3 | |
3285 | 3 | #ifdef MOZ_ACCESSIBILITY_ATK |
3286 | 3 | // Suppress atk-bridge init at startup, until mozilla accessibility is |
3287 | 3 | // initialized. This works after gnome 2.24.2. |
3288 | 3 | SaveToEnv("NO_AT_BRIDGE=1"); |
3289 | 3 | #endif |
3290 | 3 | |
3291 | 3 | // Check for application.ini overrides |
3292 | 3 | const char* override = nullptr; |
3293 | 3 | ar = CheckArg("override", &override, CheckArgFlag::CheckOSInt | CheckArgFlag::RemoveArg); |
3294 | 3 | if (ar == ARG_BAD) { |
3295 | 0 | Output(true, "Incorrect number of arguments passed to --override"); |
3296 | 0 | return 1; |
3297 | 0 | } |
3298 | 3 | if (ar == ARG_FOUND) { |
3299 | 0 | nsCOMPtr<nsIFile> overrideLF; |
3300 | 0 | rv = XRE_GetFileFromPath(override, getter_AddRefs(overrideLF)); |
3301 | 0 | if (NS_FAILED(rv)) { |
3302 | 0 | Output(true, "Error: unrecognized override.ini path.\n"); |
3303 | 0 | return 1; |
3304 | 0 | } |
3305 | 0 | |
3306 | 0 | rv = XRE_ParseAppData(overrideLF, *mAppData); |
3307 | 0 | if (NS_FAILED(rv)) { |
3308 | 0 | Output(true, "Couldn't read override.ini"); |
3309 | 0 | return 1; |
3310 | 0 | } |
3311 | 3 | } |
3312 | 3 | |
3313 | 3 | // Check sanity and correctness of app data. |
3314 | 3 | |
3315 | 3 | if (!mAppData->name) { |
3316 | 0 | Output(true, "Error: App:Name not specified in application.ini\n"); |
3317 | 0 | return 1; |
3318 | 0 | } |
3319 | 3 | if (!mAppData->buildID) { |
3320 | 0 | Output(true, "Error: App:BuildID not specified in application.ini\n"); |
3321 | 0 | return 1; |
3322 | 0 | } |
3323 | 3 | |
3324 | 3 | // XXX Originally ScopedLogging was here? Now it's in XRE_main above |
3325 | 3 | // XRE_mainInit. |
3326 | 3 | |
3327 | 3 | if (!mAppData->minVersion) { |
3328 | 0 | Output(true, "Error: Gecko:MinVersion not specified in application.ini\n"); |
3329 | 0 | return 1; |
3330 | 0 | } |
3331 | 3 | |
3332 | 3 | if (!mAppData->maxVersion) { |
3333 | 0 | // If no maxVersion is specified, we assume the app is only compatible |
3334 | 0 | // with the initial preview release. Do not increment this number ever! |
3335 | 0 | mAppData->maxVersion = "1.*"; |
3336 | 0 | } |
3337 | 3 | |
3338 | 3 | if (mozilla::Version(mAppData->minVersion) > gToolkitVersion || |
3339 | 3 | mozilla::Version(mAppData->maxVersion) < gToolkitVersion) { |
3340 | 0 | Output(true, "Error: Platform version '%s' is not compatible with\n" |
3341 | 0 | "minVersion >= %s\nmaxVersion <= %s\n", |
3342 | 0 | (const char*) gToolkitVersion, (const char*) mAppData->minVersion, |
3343 | 0 | (const char*) mAppData->maxVersion); |
3344 | 0 | return 1; |
3345 | 0 | } |
3346 | 3 | |
3347 | 3 | rv = mDirProvider.Initialize(mAppData->directory, mAppData->xreDirectory); |
3348 | 3 | if (NS_FAILED(rv)) |
3349 | 3 | return 1; |
3350 | 3 | |
3351 | 3 | if (EnvHasValue("MOZ_CRASHREPORTER")) { |
3352 | 0 | mAppData->flags |= NS_XRE_ENABLE_CRASH_REPORTER; |
3353 | 0 | } |
3354 | 3 | |
3355 | 3 | nsCOMPtr<nsIFile> xreBinDirectory; |
3356 | 3 | xreBinDirectory = mDirProvider.GetGREBinDir(); |
3357 | 3 | |
3358 | 3 | if ((mAppData->flags & NS_XRE_ENABLE_CRASH_REPORTER) && |
3359 | 3 | NS_SUCCEEDED( |
3360 | 3 | CrashReporter::SetExceptionHandler(xreBinDirectory))) { |
3361 | 0 | nsCOMPtr<nsIFile> file; |
3362 | 0 | rv = nsXREDirProvider::GetUserAppDataDirectory(getter_AddRefs(file)); |
3363 | 0 | if (NS_SUCCEEDED(rv)) { |
3364 | 0 | CrashReporter::SetUserAppDataDirectory(file); |
3365 | 0 | } |
3366 | 0 | if (mAppData->crashReporterURL) |
3367 | 0 | CrashReporter::SetServerURL(nsDependentCString(mAppData->crashReporterURL)); |
3368 | 0 |
|
3369 | 0 | // We overwrite this once we finish starting up. |
3370 | 0 | CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::StartupCrash, |
3371 | 0 | true); |
3372 | 0 |
|
3373 | 0 | // pass some basic info from the app data |
3374 | 0 | if (mAppData->vendor) |
3375 | 0 | CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::Vendor, |
3376 | 0 | nsDependentCString(mAppData->vendor)); |
3377 | 0 | if (mAppData->name) |
3378 | 0 | CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::ProductName, |
3379 | 0 | nsDependentCString(mAppData->name)); |
3380 | 0 | if (mAppData->ID) |
3381 | 0 | CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::ProductID, |
3382 | 0 | nsDependentCString(mAppData->ID)); |
3383 | 0 | if (mAppData->version) |
3384 | 0 | CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::Version, |
3385 | 0 | nsDependentCString(mAppData->version)); |
3386 | 0 | if (mAppData->buildID) |
3387 | 0 | CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::BuildID, |
3388 | 0 | nsDependentCString(mAppData->buildID)); |
3389 | 0 |
|
3390 | 0 | nsDependentCString releaseChannel(NS_STRINGIFY(MOZ_UPDATE_CHANNEL)); |
3391 | 0 | CrashReporter::AnnotateCrashReport( |
3392 | 0 | CrashReporter::Annotation::ReleaseChannel, releaseChannel); |
3393 | | #ifdef MOZ_LINKER |
3394 | | CrashReporter::AnnotateCrashReport( |
3395 | | CrashReporter::Annotation::CrashAddressLikelyWrong, |
3396 | | IsSignalHandlingBroken()); |
3397 | | #endif |
3398 | |
|
3399 | | #ifdef XP_WIN |
3400 | | nsAutoString appInitDLLs; |
3401 | | if (widget::WinUtils::GetAppInitDLLs(appInitDLLs)) { |
3402 | | CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::AppInitDLLs, |
3403 | | NS_ConvertUTF16toUTF8(appInitDLLs)); |
3404 | | } |
3405 | | #endif |
3406 | |
|
3407 | 0 | CrashReporter::SetRestartArgs(gArgc, gArgv); |
3408 | 0 |
|
3409 | 0 | // annotate other data (user id etc) |
3410 | 0 | nsCOMPtr<nsIFile> userAppDataDir; |
3411 | 0 | if (NS_SUCCEEDED(mDirProvider.GetUserAppDataDirectory( |
3412 | 0 | getter_AddRefs(userAppDataDir)))) { |
3413 | 0 | CrashReporter::SetupExtraData(userAppDataDir, |
3414 | 0 | nsDependentCString(mAppData->buildID)); |
3415 | 0 |
|
3416 | 0 | // see if we have a crashreporter-override.ini in the application directory |
3417 | 0 | nsCOMPtr<nsIFile> overrideini; |
3418 | 0 | bool exists; |
3419 | 0 | if (NS_SUCCEEDED(mDirProvider.GetAppDir()->Clone(getter_AddRefs(overrideini))) && |
3420 | 0 | NS_SUCCEEDED(overrideini->AppendNative(NS_LITERAL_CSTRING("crashreporter-override.ini"))) && |
3421 | 0 | NS_SUCCEEDED(overrideini->Exists(&exists)) && |
3422 | 0 | exists) { |
3423 | | #ifdef XP_WIN |
3424 | | nsAutoString overridePathW; |
3425 | | overrideini->GetPath(overridePathW); |
3426 | | NS_ConvertUTF16toUTF8 overridePath(overridePathW); |
3427 | | #else |
3428 | | nsAutoCString overridePath; |
3429 | 0 | overrideini->GetNativePath(overridePath); |
3430 | 0 | #endif |
3431 | 0 |
|
3432 | 0 | SaveWordToEnv("MOZ_CRASHREPORTER_STRINGS_OVERRIDE", overridePath); |
3433 | 0 | } |
3434 | 0 | } |
3435 | 0 | } |
3436 | 3 | |
3437 | | #if defined(MOZ_SANDBOX) && defined(XP_WIN) |
3438 | | if (mAppData->sandboxBrokerServices) { |
3439 | | SandboxBroker::Initialize(mAppData->sandboxBrokerServices); |
3440 | | } else { |
3441 | | #if defined(MOZ_CONTENT_SANDBOX) |
3442 | | // If we're sandboxing content and we fail to initialize, then crashing here |
3443 | | // seems like the sensible option. |
3444 | | if (BrowserTabsRemoteAutostart()) { |
3445 | | MOZ_CRASH("Failed to initialize broker services, can't continue."); |
3446 | | } |
3447 | | #endif |
3448 | | // Otherwise just warn for the moment, as most things will work. |
3449 | | NS_WARNING("Failed to initialize broker services, sandboxed processes will " |
3450 | | "fail to start."); |
3451 | | } |
3452 | | if (mAppData->sandboxPermissionsService) { |
3453 | | SandboxPermissions::Initialize(mAppData->sandboxPermissionsService, |
3454 | | nullptr); |
3455 | | } |
3456 | | #endif |
3457 | | |
3458 | | #ifdef XP_MACOSX |
3459 | | // Set up ability to respond to system (Apple) events. This must occur before |
3460 | | // ProcessUpdates to ensure that links clicked in external applications aren't |
3461 | | // lost when updates are pending. |
3462 | | SetupMacApplicationDelegate(); |
3463 | | |
3464 | | if (EnvHasValue("MOZ_LAUNCHED_CHILD")) { |
3465 | | // This is needed, on relaunch, to force the OS to use the "Cocoa Dock |
3466 | | // API". Otherwise the call to ReceiveNextEvent() below will make it |
3467 | | // use the "Carbon Dock API". For more info see bmo bug 377166. |
3468 | | EnsureUseCocoaDockAPI(); |
3469 | | |
3470 | | // When the app relaunches, the original process exits. This causes |
3471 | | // the dock tile to stop bouncing, lose the "running" triangle, and |
3472 | | // if the tile does not permanently reside in the Dock, even disappear. |
3473 | | // This can be confusing to the user, who is expecting the app to launch. |
3474 | | // Calling ReceiveNextEvent without requesting any event is enough to |
3475 | | // cause a dock tile for the child process to appear. |
3476 | | const EventTypeSpec kFakeEventList[] = { { INT_MAX, INT_MAX } }; |
3477 | | EventRef event; |
3478 | | ::ReceiveNextEvent(GetEventTypeCount(kFakeEventList), kFakeEventList, |
3479 | | kEventDurationNoWait, false, &event); |
3480 | | } |
3481 | | |
3482 | | if (CheckArg("foreground")) { |
3483 | | // The original process communicates that it was in the foreground by |
3484 | | // adding this argument. This new process, which is taking over for |
3485 | | // the old one, should make itself the active application. |
3486 | | ProcessSerialNumber psn; |
3487 | | if (::GetCurrentProcess(&psn) == noErr) |
3488 | | ::SetFrontProcess(&psn); |
3489 | | } |
3490 | | #endif |
3491 | | |
3492 | 3 | SaveToEnv("MOZ_LAUNCHED_CHILD="); |
3493 | 3 | |
3494 | 3 | // On Windows, the -os-restarted command line switch lets us know when we are |
3495 | 3 | // restarted via RegisterApplicationRestart. May be used for other OSes later. |
3496 | 3 | if (CheckArg("os-restarted", nullptr, CheckArgFlag::RemoveArg) == ARG_FOUND) { |
3497 | 0 | gRestartedByOS = true; |
3498 | 0 | } |
3499 | 3 | |
3500 | 3 | gRestartArgc = gArgc; |
3501 | 3 | gRestartArgv = (char**) malloc(sizeof(char*) * (gArgc + 1 + (override ? 2 : 0))); |
3502 | 3 | if (!gRestartArgv) { |
3503 | 0 | return 1; |
3504 | 0 | } |
3505 | 3 | |
3506 | 3 | int i; |
3507 | 18 | for (i = 0; i < gArgc; ++i) { |
3508 | 15 | gRestartArgv[i] = gArgv[i]; |
3509 | 15 | } |
3510 | 3 | |
3511 | 3 | // Add the -override argument back (it is removed automatically be CheckArg) if there is one |
3512 | 3 | if (override) { |
3513 | 0 | gRestartArgv[gRestartArgc++] = const_cast<char*>("-override"); |
3514 | 0 | gRestartArgv[gRestartArgc++] = const_cast<char*>(override); |
3515 | 0 | } |
3516 | 3 | |
3517 | 3 | gRestartArgv[gRestartArgc] = nullptr; |
3518 | 3 | |
3519 | 3 | Maybe<bool> safeModeRequested = IsSafeModeRequested(gArgc, gArgv); |
3520 | 3 | if (!safeModeRequested) { |
3521 | 0 | return 1; |
3522 | 0 | } |
3523 | 3 | |
3524 | 3 | gSafeMode = safeModeRequested.value(); |
3525 | 3 | |
3526 | | #ifdef XP_WIN |
3527 | | { |
3528 | | // Add CPU microcode version to the crash report as "CPUMicrocodeVersion". |
3529 | | // It feels like this code may belong in nsSystemInfo instead. |
3530 | | int cpuUpdateRevision = -1; |
3531 | | HKEY key; |
3532 | | static const WCHAR keyName[] = |
3533 | | L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0"; |
3534 | | |
3535 | | if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, keyName , 0, KEY_QUERY_VALUE, &key) == ERROR_SUCCESS) { |
3536 | | |
3537 | | DWORD updateRevision[2]; |
3538 | | DWORD len = sizeof(updateRevision); |
3539 | | DWORD vtype; |
3540 | | |
3541 | | // Windows 7 uses "Update Signature", 8 uses "Update Revision". |
3542 | | // For AMD CPUs, "CurrentPatchLevel" is sometimes used. |
3543 | | // Take the first one we find. |
3544 | | LPCWSTR choices[] = {L"Update Signature", L"Update Revision", L"CurrentPatchLevel"}; |
3545 | | for (size_t oneChoice=0; oneChoice<ArrayLength(choices); oneChoice++) { |
3546 | | if (RegQueryValueExW(key, choices[oneChoice], |
3547 | | 0, &vtype, |
3548 | | reinterpret_cast<LPBYTE>(updateRevision), |
3549 | | &len) == ERROR_SUCCESS) { |
3550 | | if (vtype == REG_BINARY && len == sizeof(updateRevision)) { |
3551 | | // The first word is unused |
3552 | | cpuUpdateRevision = static_cast<int>(updateRevision[1]); |
3553 | | break; |
3554 | | } else if (vtype == REG_DWORD && len == sizeof(updateRevision[0])) { |
3555 | | cpuUpdateRevision = static_cast<int>(updateRevision[0]); |
3556 | | break; |
3557 | | } |
3558 | | } |
3559 | | } |
3560 | | } |
3561 | | |
3562 | | if (cpuUpdateRevision > 0) { |
3563 | | CrashReporter::AnnotateCrashReport( |
3564 | | CrashReporter::Annotation::CPUMicrocodeVersion, |
3565 | | nsPrintfCString("0x%x", cpuUpdateRevision)); |
3566 | | } |
3567 | | } |
3568 | | #endif |
3569 | | |
3570 | 3 | CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::SafeMode, |
3571 | 3 | gSafeMode); |
3572 | 3 | |
3573 | 3 | // Handle --no-remote and --new-instance command line arguments. Setup |
3574 | 3 | // the environment to better accommodate other components and various |
3575 | 3 | // restart scenarios. |
3576 | 3 | ar = CheckArg("no-remote", nullptr, CheckArgFlag::CheckOSInt | CheckArgFlag::RemoveArg); |
3577 | 3 | if (ar == ARG_BAD) { |
3578 | 0 | PR_fprintf(PR_STDERR, "Error: argument --no-remote is invalid when argument --osint is specified\n"); |
3579 | 0 | return 1; |
3580 | 0 | } |
3581 | 3 | if (ar == ARG_FOUND) { |
3582 | 0 | SaveToEnv("MOZ_NO_REMOTE=1"); |
3583 | 0 | } |
3584 | 3 | |
3585 | 3 | ar = CheckArg("new-instance", nullptr, CheckArgFlag::CheckOSInt | CheckArgFlag::RemoveArg); |
3586 | 3 | if (ar == ARG_BAD) { |
3587 | 0 | PR_fprintf(PR_STDERR, "Error: argument --new-instance is invalid when argument --osint is specified\n"); |
3588 | 0 | return 1; |
3589 | 0 | } |
3590 | 3 | if (ar == ARG_FOUND) { |
3591 | 0 | SaveToEnv("MOZ_NEW_INSTANCE=1"); |
3592 | 0 | } |
3593 | 3 | |
3594 | 3 | // Handle --help and --version command line arguments. |
3595 | 3 | // They should return quickly, so we deal with them here. |
3596 | 3 | if (CheckArg("h") || CheckArg("help") || CheckArg("?")) { |
3597 | 0 | DumpHelp(); |
3598 | 0 | *aExitFlag = true; |
3599 | 0 | return 0; |
3600 | 0 | } |
3601 | 3 | |
3602 | 3 | if (CheckArg("v") || CheckArg("version")) { |
3603 | 0 | DumpVersion(); |
3604 | 0 | *aExitFlag = true; |
3605 | 0 | return 0; |
3606 | 0 | } |
3607 | 3 | |
3608 | 3 | rv = XRE_InitCommandLine(gArgc, gArgv); |
3609 | 3 | NS_ENSURE_SUCCESS(rv, 1); |
3610 | 3 | |
3611 | 3 | // Check for --register, which registers chrome and then exits immediately. |
3612 | 3 | ar = CheckArg("register", nullptr, CheckArgFlag::CheckOSInt | CheckArgFlag::RemoveArg); |
3613 | 3 | if (ar == ARG_BAD) { |
3614 | 0 | PR_fprintf(PR_STDERR, "Error: argument --register is invalid when argument --osint is specified\n"); |
3615 | 0 | return 1; |
3616 | 0 | } |
3617 | 3 | if (ar == ARG_FOUND) { |
3618 | 0 | ScopedXPCOMStartup xpcom; |
3619 | 0 | rv = xpcom.Initialize(); |
3620 | 0 | NS_ENSURE_SUCCESS(rv, 1); |
3621 | 0 | { |
3622 | 0 | nsCOMPtr<nsIChromeRegistry> chromeReg = |
3623 | 0 | mozilla::services::GetChromeRegistryService(); |
3624 | 0 | NS_ENSURE_TRUE(chromeReg, 1); |
3625 | 0 |
|
3626 | 0 | chromeReg->CheckForNewChrome(); |
3627 | 0 | } |
3628 | 0 | *aExitFlag = true; |
3629 | 0 | return 0; |
3630 | 3 | } |
3631 | 3 | |
3632 | 3 | return 0; |
3633 | 3 | } |
3634 | | |
3635 | | #ifdef XP_WIN |
3636 | | static bool QueryOneWMIProperty(IWbemServices* aServices, |
3637 | | const wchar_t* aWMIClass, |
3638 | | const wchar_t* aProperty, |
3639 | | VARIANT* aResult) |
3640 | | { |
3641 | | RefPtr<IEnumWbemClassObject> enumerator; |
3642 | | |
3643 | | _bstr_t query(L"SELECT * FROM "); |
3644 | | query += _bstr_t(aWMIClass); |
3645 | | |
3646 | | HRESULT hr = aServices->ExecQuery(_bstr_t(L"WQL"), query, |
3647 | | WBEM_FLAG_FORWARD_ONLY | |
3648 | | WBEM_FLAG_RETURN_IMMEDIATELY, |
3649 | | nullptr, getter_AddRefs(enumerator)); |
3650 | | |
3651 | | if (FAILED(hr) || !enumerator) { |
3652 | | return false; |
3653 | | } |
3654 | | |
3655 | | RefPtr<IWbemClassObject> classObject; |
3656 | | ULONG results; |
3657 | | |
3658 | | hr = enumerator->Next(WBEM_INFINITE, 1, getter_AddRefs(classObject), &results); |
3659 | | |
3660 | | if (FAILED(hr) || results == 0) { |
3661 | | return false; |
3662 | | } |
3663 | | |
3664 | | hr = classObject->Get(aProperty, 0, aResult, 0, 0); |
3665 | | |
3666 | | return SUCCEEDED(hr); |
3667 | | } |
3668 | | |
3669 | | /** |
3670 | | * Uses WMI to read some information that may be useful for diagnosing |
3671 | | * crashes. This function is best-effort; failures shouldn't burden the |
3672 | | * caller. COM must be initialized before calling. |
3673 | | */ |
3674 | | |
3675 | | static const char kMemoryErrorCorrectionValues[][15] = { |
3676 | | "Reserved", // 0 |
3677 | | "Other", // 1 |
3678 | | "Unknown", // 2 |
3679 | | "None", // 3 |
3680 | | "Parity", // 4 |
3681 | | "Single-bit ECC", // 5 |
3682 | | "Multi-bit ECC", // 6 |
3683 | | "CRC" // 7 |
3684 | | }; |
3685 | | |
3686 | | static void AnnotateWMIData() |
3687 | | { |
3688 | | RefPtr<IWbemLocator> locator; |
3689 | | |
3690 | | HRESULT hr = CoCreateInstance(CLSID_WbemLocator, nullptr, CLSCTX_INPROC_SERVER, |
3691 | | IID_IWbemLocator, getter_AddRefs(locator)); |
3692 | | |
3693 | | if (FAILED(hr)) { |
3694 | | return; |
3695 | | } |
3696 | | |
3697 | | RefPtr<IWbemServices> services; |
3698 | | |
3699 | | hr = locator->ConnectServer(_bstr_t(L"ROOT\\CIMV2"), nullptr, nullptr, nullptr, |
3700 | | 0, nullptr, nullptr, getter_AddRefs(services)); |
3701 | | |
3702 | | if (FAILED(hr)) { |
3703 | | return; |
3704 | | } |
3705 | | |
3706 | | hr = CoSetProxyBlanket(services, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, nullptr, |
3707 | | RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, |
3708 | | nullptr, EOAC_NONE); |
3709 | | |
3710 | | if (FAILED(hr)) { |
3711 | | return; |
3712 | | } |
3713 | | |
3714 | | |
3715 | | VARIANT value; |
3716 | | VariantInit(&value); |
3717 | | |
3718 | | // Annotate information about the system manufacturer. |
3719 | | if (QueryOneWMIProperty(services, L"Win32_BIOS", L"Manufacturer", &value) && |
3720 | | V_VT(&value) == VT_BSTR) { |
3721 | | CrashReporter::AnnotateCrashReport( |
3722 | | CrashReporter::Annotation::BIOS_Manufacturer, |
3723 | | NS_ConvertUTF16toUTF8(V_BSTR(&value))); |
3724 | | } |
3725 | | |
3726 | | VariantClear(&value); |
3727 | | |
3728 | | // Annotate information about type of memory error correction. |
3729 | | if (QueryOneWMIProperty(services, L"Win32_PhysicalMemoryArray", |
3730 | | L"MemoryErrorCorrection", &value) && |
3731 | | V_VT(&value) == VT_I4) { |
3732 | | long valueInt = V_I4(&value); |
3733 | | nsCString valueString; |
3734 | | if (valueInt < 0 || valueInt >= long(ArrayLength(kMemoryErrorCorrectionValues))) { |
3735 | | valueString.AssignLiteral("Unexpected value"); |
3736 | | } else { |
3737 | | valueString.AssignASCII(kMemoryErrorCorrectionValues[valueInt]); |
3738 | | } |
3739 | | CrashReporter::AnnotateCrashReport( |
3740 | | CrashReporter::Annotation::MemoryErrorCorrection, valueString); |
3741 | | } |
3742 | | |
3743 | | VariantClear(&value); |
3744 | | } |
3745 | | |
3746 | | static void PR_CALLBACK AnnotateWMIData_ThreadStart(void*) |
3747 | | { |
3748 | | HRESULT hr = CoInitialize(nullptr); |
3749 | | |
3750 | | if (FAILED(hr)) { |
3751 | | return; |
3752 | | } |
3753 | | |
3754 | | AnnotateWMIData(); |
3755 | | |
3756 | | CoUninitialize(); |
3757 | | } |
3758 | | #endif // XP_WIN |
3759 | | |
3760 | | #if defined(XP_LINUX) && !defined(ANDROID) |
3761 | | |
3762 | | static void |
3763 | | AnnotateLSBRelease(void*) |
3764 | 0 | { |
3765 | 0 | nsCString dist, desc, release, codename; |
3766 | 0 | if (widget::lsb::GetLSBRelease(dist, desc, release, codename)) { |
3767 | 0 | CrashReporter::AppendAppNotesToCrashReport(desc); |
3768 | 0 | } |
3769 | 0 | } |
3770 | | |
3771 | | #endif // defined(XP_LINUX) && !defined(ANDROID) |
3772 | | |
3773 | | #ifdef XP_WIN |
3774 | | static void ReadAheadDll(const wchar_t* dllName) { |
3775 | | wchar_t dllPath[MAX_PATH]; |
3776 | | if (ConstructSystem32Path(dllName, dllPath, MAX_PATH)) { |
3777 | | ReadAheadLib(dllPath); |
3778 | | } |
3779 | | } |
3780 | | |
3781 | | static void PR_CALLBACK ReadAheadDlls_ThreadStart(void *) { |
3782 | | // Load DataExchange.dll and twinapi.appcore.dll for nsWindow::EnableDragDrop |
3783 | | ReadAheadDll(L"DataExchange.dll"); |
3784 | | ReadAheadDll(L"twinapi.appcore.dll"); |
3785 | | |
3786 | | // Load twinapi.dll for WindowsUIUtils::UpdateTabletModeState |
3787 | | ReadAheadDll(L"twinapi.dll"); |
3788 | | |
3789 | | // Load explorerframe.dll for WinTaskbar::Initialize |
3790 | | ReadAheadDll(L"ExplorerFrame.dll"); |
3791 | | } |
3792 | | #endif |
3793 | | |
3794 | | namespace mozilla { |
3795 | | ShutdownChecksMode gShutdownChecks = SCM_NOTHING; |
3796 | | } // namespace mozilla |
3797 | | |
3798 | 3 | static void SetShutdownChecks() { |
3799 | 3 | // Set default first. On debug builds we crash. On nightly and local |
3800 | 3 | // builds we record. Nightlies will then send the info via telemetry, |
3801 | 3 | // but it is usefull to have the data in about:telemetry in local builds |
3802 | 3 | // too. |
3803 | 3 | |
3804 | | #ifdef DEBUG |
3805 | | #if defined(MOZ_CODE_COVERAGE) |
3806 | | gShutdownChecks = SCM_NOTHING; |
3807 | | #else |
3808 | | gShutdownChecks = SCM_CRASH; |
3809 | | #endif // MOZ_CODE_COVERAGE |
3810 | | #else |
3811 | 3 | const char* releaseChannel = NS_STRINGIFY(MOZ_UPDATE_CHANNEL); |
3812 | 3 | if (strcmp(releaseChannel, "nightly") == 0 || |
3813 | 3 | strcmp(releaseChannel, "default") == 0) { |
3814 | 3 | gShutdownChecks = SCM_RECORD; |
3815 | 3 | } else { |
3816 | 0 | gShutdownChecks = SCM_NOTHING; |
3817 | 0 | } |
3818 | 3 | #endif // DEBUG |
3819 | 3 | |
3820 | 3 | // We let an environment variable override the default so that addons |
3821 | 3 | // authors can use it for debugging shutdown with released firefox versions. |
3822 | 3 | const char* mozShutdownChecksEnv = PR_GetEnv("MOZ_SHUTDOWN_CHECKS"); |
3823 | 3 | if (mozShutdownChecksEnv) { |
3824 | 0 | if (strcmp(mozShutdownChecksEnv, "crash") == 0) { |
3825 | 0 | gShutdownChecks = SCM_CRASH; |
3826 | 0 | } else if (strcmp(mozShutdownChecksEnv, "record") == 0) { |
3827 | 0 | gShutdownChecks = SCM_RECORD; |
3828 | 0 | } else if (strcmp(mozShutdownChecksEnv, "nothing") == 0) { |
3829 | 0 | gShutdownChecks = SCM_NOTHING; |
3830 | 0 | } |
3831 | 0 | } |
3832 | 3 | |
3833 | 3 | } |
3834 | | |
3835 | | namespace mozilla { |
3836 | | namespace startup { |
3837 | | Result<nsCOMPtr<nsIFile>, nsresult> |
3838 | | GetIncompleteStartupFile(nsIFile* aProfLD) |
3839 | 0 | { |
3840 | 0 | nsCOMPtr<nsIFile> crashFile; |
3841 | 0 | MOZ_TRY(aProfLD->Clone(getter_AddRefs(crashFile))); |
3842 | 0 | MOZ_TRY(crashFile->Append(FILE_STARTUP_INCOMPLETE)); |
3843 | 0 | return std::move(crashFile); |
3844 | 0 | } |
3845 | | } |
3846 | | } |
3847 | | |
3848 | | // Check whether the last startup attempt resulted in a crash within the |
3849 | | // last 6 hours. |
3850 | | // Note that this duplicates the logic in nsAppStartup::TrackStartupCrashBegin, |
3851 | | // which runs too late for our purposes. |
3852 | | Result<bool, nsresult> |
3853 | | XREMain::CheckLastStartupWasCrash() |
3854 | 0 | { |
3855 | 0 | constexpr int32_t MAX_TIME_SINCE_STARTUP = 6 * 60 * 60 * 1000; |
3856 | 0 |
|
3857 | 0 | nsCOMPtr<nsIFile> crashFile; |
3858 | 0 | MOZ_TRY_VAR(crashFile, GetIncompleteStartupFile(mProfLD)); |
3859 | 0 |
|
3860 | 0 | // Attempt to create the incomplete startup canary file. If the file already |
3861 | 0 | // exists, this fails, and we know the last startup was a success. If it |
3862 | 0 | // doesn't already exist, it is created, and will be removed at the end of |
3863 | 0 | // the startup crash detection window. |
3864 | 0 | AutoFDClose fd; |
3865 | 0 | Unused << crashFile->OpenNSPRFileDesc(PR_WRONLY | PR_CREATE_FILE | PR_EXCL, |
3866 | 0 | 0666, &fd.rwget()); |
3867 | 0 | if (fd) { |
3868 | 0 | return false; |
3869 | 0 | } |
3870 | 0 | |
3871 | 0 | PRTime lastModifiedTime; |
3872 | 0 | MOZ_TRY(crashFile->GetLastModifiedTime(&lastModifiedTime)); |
3873 | 0 |
|
3874 | 0 | // If the file exists, and was created within the appropriate time window, |
3875 | 0 | // the last startup was recent and resulted in a crash. |
3876 | 0 | PRTime now = PR_Now() / PR_USEC_PER_MSEC; |
3877 | 0 | return now - lastModifiedTime <= MAX_TIME_SINCE_STARTUP; |
3878 | 0 | } |
3879 | | |
3880 | | /* |
3881 | | * XRE_mainStartup - Initializes the profile and various other services. |
3882 | | * Main() will exit early if either return value != 0 or if aExitFlag is |
3883 | | * true. |
3884 | | */ |
3885 | | int |
3886 | | XREMain::XRE_mainStartup(bool* aExitFlag) |
3887 | 3 | { |
3888 | 3 | nsresult rv; |
3889 | 3 | |
3890 | 3 | if (!aExitFlag) |
3891 | 0 | return 1; |
3892 | 3 | *aExitFlag = false; |
3893 | 3 | |
3894 | 3 | SetShutdownChecks(); |
3895 | 3 | |
3896 | 3 | // Enable Telemetry IO Reporting on DEBUG, nightly and local builds |
3897 | | #ifdef DEBUG |
3898 | | mozilla::Telemetry::InitIOReporting(gAppData->xreDirectory); |
3899 | | #else |
3900 | | { |
3901 | 3 | const char* releaseChannel = NS_STRINGIFY(MOZ_UPDATE_CHANNEL); |
3902 | 3 | if (strcmp(releaseChannel, "nightly") == 0 || |
3903 | 3 | strcmp(releaseChannel, "default") == 0) { |
3904 | 3 | mozilla::Telemetry::InitIOReporting(gAppData->xreDirectory); |
3905 | 3 | } |
3906 | 3 | } |
3907 | 3 | #endif /* DEBUG */ |
3908 | 3 | |
3909 | | #if defined(XP_WIN) |
3910 | | // Enable the HeapEnableTerminationOnCorruption exploit mitigation. We ignore |
3911 | | // the return code because it always returns success, although it has no |
3912 | | // effect on Windows older than XP SP3. |
3913 | | HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0); |
3914 | | #endif /* XP_WIN */ |
3915 | | |
3916 | 3 | #if defined(MOZ_WIDGET_GTK) || defined(MOZ_ENABLE_XREMOTE) |
3917 | 3 | // Stash DESKTOP_STARTUP_ID in malloc'ed memory because gtk_init will clear it. |
3918 | 3 | #define HAVE_DESKTOP_STARTUP_ID |
3919 | 3 | const char* desktopStartupIDEnv = PR_GetEnv("DESKTOP_STARTUP_ID"); |
3920 | 3 | if (desktopStartupIDEnv) { |
3921 | 0 | mDesktopStartupID.Assign(desktopStartupIDEnv); |
3922 | 0 | } |
3923 | 3 | #endif |
3924 | 3 | |
3925 | 3 | #if defined(MOZ_WIDGET_GTK) |
3926 | 3 | // setup for private colormap. Ideally we'd like to do this |
3927 | 3 | // in nsAppShell::Create, but we need to get in before gtk |
3928 | 3 | // has been initialized to make sure everything is running |
3929 | 3 | // consistently. |
3930 | 3 | |
3931 | 3 | // Set program name to the one defined in application.ini. |
3932 | 3 | { |
3933 | 3 | nsAutoCString program(gAppData->name); |
3934 | 3 | ToLowerCase(program); |
3935 | 3 | g_set_prgname(program.get()); |
3936 | 3 | } |
3937 | 3 | |
3938 | 3 | // Initialize GTK here for splash. |
3939 | 3 | |
3940 | 3 | #if defined(MOZ_WIDGET_GTK) && defined(MOZ_X11) |
3941 | 3 | // Disable XInput2 multidevice support due to focus bugginess. |
3942 | 3 | // See bugs 1182700, 1170342. |
3943 | 3 | // gdk_disable_multidevice() affects Gdk X11 backend only, |
3944 | 3 | // the multidevice support is always enabled on Wayland backend. |
3945 | 3 | const char* useXI2 = PR_GetEnv("MOZ_USE_XINPUT2"); |
3946 | 3 | if (!useXI2 || (*useXI2 == '0')) |
3947 | 3 | gdk_disable_multidevice(); |
3948 | 3 | #endif |
3949 | 3 | |
3950 | 3 | // Open the display ourselves instead of using gtk_init, so that we can |
3951 | 3 | // close it without fear that one day gtk might clean up the display it |
3952 | 3 | // opens. |
3953 | 3 | if (!gtk_parse_args(&gArgc, &gArgv)) |
3954 | 0 | return 1; |
3955 | 3 | #endif /* MOZ_WIDGET_GTK */ |
3956 | 3 | |
3957 | 3 | #ifdef FUZZING |
3958 | 3 | if (PR_GetEnv("FUZZER")) { |
3959 | 3 | *aExitFlag = true; |
3960 | 3 | return mozilla::fuzzerRunner->Run(&gArgc, &gArgv); |
3961 | 3 | } |
3962 | 0 | #endif |
3963 | 0 | |
3964 | 0 | if (PR_GetEnv("MOZ_RUN_GTEST")) { |
3965 | 0 | int result; |
3966 | | #ifdef XP_WIN |
3967 | | UseParentConsole(); |
3968 | | #endif |
3969 | | // RunGTest will only be set if we're in xul-unit |
3970 | 0 | if (mozilla::RunGTest) { |
3971 | 0 | gIsGtest = true; |
3972 | 0 | result = mozilla::RunGTest(&gArgc, gArgv); |
3973 | 0 | gIsGtest = false; |
3974 | 0 | } else { |
3975 | 0 | result = 1; |
3976 | 0 | printf("TEST-UNEXPECTED-FAIL | gtest | Not compiled with enable-tests\n"); |
3977 | 0 | } |
3978 | 0 | *aExitFlag = true; |
3979 | 0 | return result; |
3980 | 0 | } |
3981 | 0 |
|
3982 | 0 | #ifdef MOZ_X11 |
3983 | 0 | // Init X11 in thread-safe mode. Must be called prior to the first call to XOpenDisplay |
3984 | 0 | // (called inside gdk_display_open). This is a requirement for off main tread compositing. |
3985 | 0 | if (!gfxPlatform::IsHeadless()) { |
3986 | 0 | XInitThreads(); |
3987 | 0 | } |
3988 | 0 | #endif |
3989 | 0 | #if defined(MOZ_WIDGET_GTK) |
3990 | 0 | if (!gfxPlatform::IsHeadless()) { |
3991 | 0 | const char *display_name = nullptr; |
3992 | 0 | bool saveDisplayArg = false; |
3993 | 0 |
|
3994 | 0 | // display_name is owned by gdk. |
3995 | 0 | display_name = gdk_get_display_arg_name(); |
3996 | 0 | // if --display argument is given make sure it's |
3997 | 0 | // also passed to ContentChild::Init() by MOZ_GDK_DISPLAY. |
3998 | 0 | if (display_name) { |
3999 | 0 | SaveWordToEnv("MOZ_GDK_DISPLAY", nsDependentCString(display_name)); |
4000 | 0 | saveDisplayArg = true; |
4001 | 0 | } |
4002 | 0 |
|
4003 | 0 | // On Wayland disabled builds read X11 DISPLAY env exclusively |
4004 | 0 | // and don't care about different displays. |
4005 | 0 | #if !defined(MOZ_WAYLAND) |
4006 | 0 | if (!display_name) { |
4007 | 0 | display_name = PR_GetEnv("DISPLAY"); |
4008 | 0 | if (!display_name) { |
4009 | 0 | PR_fprintf(PR_STDERR, |
4010 | 0 | "Error: no DISPLAY environment variable specified\n"); |
4011 | 0 | return 1; |
4012 | 0 | } |
4013 | 0 | } |
4014 | 0 | #endif |
4015 | 0 | |
4016 | 0 | if (display_name) { |
4017 | 0 | mGdkDisplay = gdk_display_open(display_name); |
4018 | 0 | if (!mGdkDisplay) { |
4019 | 0 | PR_fprintf(PR_STDERR, "Error: cannot open display: %s\n", display_name); |
4020 | 0 | return 1; |
4021 | 0 | } |
4022 | 0 | gdk_display_manager_set_default_display(gdk_display_manager_get(), |
4023 | 0 | mGdkDisplay); |
4024 | 0 | if (saveDisplayArg) { |
4025 | 0 | if (GDK_IS_X11_DISPLAY(mGdkDisplay)) { |
4026 | 0 | SaveWordToEnv("DISPLAY", nsDependentCString(display_name)); |
4027 | 0 | } |
4028 | | #ifdef MOZ_WAYLAND |
4029 | | else if (GDK_IS_WAYLAND_DISPLAY(mGdkDisplay)) { |
4030 | | SaveWordToEnv("WAYLAND_DISPLAY", nsDependentCString(display_name)); |
4031 | | } |
4032 | | #endif |
4033 | | } |
4034 | 0 | } |
4035 | 0 | #ifdef MOZ_WIDGET_GTK |
4036 | 0 | else { |
4037 | 0 | mGdkDisplay = gdk_display_manager_open_display(gdk_display_manager_get(), |
4038 | 0 | nullptr); |
4039 | 0 | } |
4040 | 0 | #endif |
4041 | 0 | } |
4042 | 0 | else { |
4043 | 0 | mDisableRemote = true; |
4044 | 0 | } |
4045 | 0 | #endif |
4046 | 0 | #ifdef MOZ_ENABLE_XREMOTE |
4047 | 0 | // handle --remote now that xpcom is fired up |
4048 | 0 | bool newInstance; |
4049 | 0 | { |
4050 | 0 | char *e = PR_GetEnv("MOZ_NO_REMOTE"); |
4051 | 0 | mDisableRemote = (mDisableRemote || (e && *e)); |
4052 | 0 | if (mDisableRemote) { |
4053 | 0 | newInstance = true; |
4054 | 0 | } else { |
4055 | 0 | e = PR_GetEnv("MOZ_NEW_INSTANCE"); |
4056 | 0 | newInstance = (e && *e); |
4057 | 0 | } |
4058 | 0 | } |
4059 | 0 |
|
4060 | 0 | if (!newInstance) { |
4061 | 0 | nsAutoCString program(gAppData->remotingName); |
4062 | 0 | ToLowerCase(program); |
4063 | 0 |
|
4064 | 0 | const char* username = getenv("LOGNAME"); |
4065 | 0 | const char* profile = nullptr; |
4066 | 0 |
|
4067 | 0 | RemoteResult rr = ParseRemoteCommandLine(program, &profile, &username); |
4068 | 0 | if (rr == REMOTE_ARG_BAD) { |
4069 | 0 | return 1; |
4070 | 0 | } |
4071 | 0 | |
4072 | 0 | if (!username) { |
4073 | 0 | struct passwd *pw = getpwuid(geteuid()); |
4074 | 0 | if (pw && pw->pw_name) { |
4075 | 0 | // Beware that another call to getpwent/getpwname/getpwuid will overwrite |
4076 | 0 | // pw, but we don't have such another call between here and when username |
4077 | 0 | // is used last. |
4078 | 0 | username = pw->pw_name; |
4079 | 0 | } |
4080 | 0 | } |
4081 | 0 |
|
4082 | 0 | nsCOMPtr<nsIFile> mutexDir; |
4083 | 0 | rv = GetSpecialSystemDirectory(OS_TemporaryDirectory, getter_AddRefs(mutexDir)); |
4084 | 0 | if (NS_SUCCEEDED(rv)) { |
4085 | 0 | nsAutoCString mutexPath = program + NS_LITERAL_CSTRING("_"); |
4086 | 0 | // In the unlikely even that LOGNAME is not set and getpwuid failed, just |
4087 | 0 | // don't put the username in the mutex directory. It will conflict with |
4088 | 0 | // other users mutex, but the worst that can happen is that they wait for |
4089 | 0 | // MOZ_XREMOTE_START_TIMEOUT_SEC during startup in that case. |
4090 | 0 | if (username) { |
4091 | 0 | mutexPath.Append(username); |
4092 | 0 | } |
4093 | 0 | if (profile) { |
4094 | 0 | mutexPath.Append(NS_LITERAL_CSTRING("_") + nsDependentCString(profile)); |
4095 | 0 | } |
4096 | 0 | mutexDir->AppendNative(mutexPath); |
4097 | 0 |
|
4098 | 0 | rv = mutexDir->Create(nsIFile::DIRECTORY_TYPE, 0700); |
4099 | 0 | if (NS_SUCCEEDED(rv) || rv == NS_ERROR_FILE_ALREADY_EXISTS) { |
4100 | 0 | mRemoteLockDir = mutexDir; |
4101 | 0 | } |
4102 | 0 | } |
4103 | 0 |
|
4104 | 0 | if (mRemoteLockDir) { |
4105 | 0 | const TimeStamp epoch = mozilla::TimeStamp::Now(); |
4106 | 0 | do { |
4107 | 0 | rv = mRemoteLock.Lock(mRemoteLockDir, nullptr); |
4108 | 0 | if (NS_SUCCEEDED(rv)) |
4109 | 0 | break; |
4110 | 0 | sched_yield(); |
4111 | 0 | } while ((TimeStamp::Now() - epoch) |
4112 | 0 | < TimeDuration::FromSeconds(MOZ_XREMOTE_START_TIMEOUT_SEC)); |
4113 | 0 | if (NS_FAILED(rv)) { |
4114 | 0 | NS_WARNING("Cannot lock XRemote start mutex"); |
4115 | 0 | } |
4116 | 0 | } |
4117 | 0 |
|
4118 | 0 | // Try to remote the entire command line. If this fails, start up normally. |
4119 | 0 | const char* desktopStartupIDPtr = |
4120 | 0 | mDesktopStartupID.IsEmpty() ? nullptr : mDesktopStartupID.get(); |
4121 | 0 |
|
4122 | 0 | rr = StartRemoteClient(desktopStartupIDPtr, program, profile, username); |
4123 | 0 | if (rr == REMOTE_FOUND) { |
4124 | 0 | *aExitFlag = true; |
4125 | 0 | return 0; |
4126 | 0 | } |
4127 | 0 | if (rr == REMOTE_ARG_BAD) { |
4128 | 0 | return 1; |
4129 | 0 | } |
4130 | 0 | } |
4131 | 0 | #endif |
4132 | 0 | #if defined(MOZ_WIDGET_GTK) |
4133 | 0 | g_set_application_name(mAppData->name); |
4134 | 0 | gtk_window_set_auto_startup_notification(false); |
4135 | 0 |
|
4136 | 0 | #endif /* defined(MOZ_WIDGET_GTK) */ |
4137 | 0 | #ifdef MOZ_X11 |
4138 | 0 | // Do this after initializing GDK, or GDK will install its own handler. |
4139 | 0 | XRE_InstallX11ErrorHandler(); |
4140 | 0 | #endif |
4141 | 0 |
|
4142 | 0 | // Call the code to install our handler |
4143 | | #ifdef MOZ_JPROF |
4144 | | setupProfilingStuff(); |
4145 | | #endif |
4146 | |
|
4147 | 0 | rv = NS_CreateNativeAppSupport(getter_AddRefs(mNativeApp)); |
4148 | 0 | if (NS_FAILED(rv)) |
4149 | 0 | return 1; |
4150 | 0 | |
4151 | 0 | bool canRun = false; |
4152 | 0 | rv = mNativeApp->Start(&canRun); |
4153 | 0 | if (NS_FAILED(rv) || !canRun) { |
4154 | 0 | return 1; |
4155 | 0 | } |
4156 | 0 | |
4157 | 0 | #if defined(HAVE_DESKTOP_STARTUP_ID) && defined(MOZ_WIDGET_GTK) |
4158 | 0 | // DESKTOP_STARTUP_ID is cleared now, |
4159 | 0 | // we recover it in case we need a restart. |
4160 | 0 | if (!mDesktopStartupID.IsEmpty()) { |
4161 | 0 | nsAutoCString desktopStartupEnv; |
4162 | 0 | desktopStartupEnv.AssignLiteral("DESKTOP_STARTUP_ID="); |
4163 | 0 | desktopStartupEnv.Append(mDesktopStartupID); |
4164 | 0 | // Leak it with extreme prejudice! |
4165 | 0 | PR_SetEnv(ToNewCString(desktopStartupEnv)); |
4166 | 0 | } |
4167 | 0 | #endif |
4168 | 0 |
|
4169 | 0 | // Support exiting early for testing startup sequence. Bug 1360493 |
4170 | 0 | if (CheckArg("test-launch-without-hang")) { |
4171 | 0 | *aExitFlag = true; |
4172 | 0 | return 0; |
4173 | 0 | } |
4174 | 0 | |
4175 | 0 | #if defined(MOZ_UPDATER) && !defined(MOZ_WIDGET_ANDROID) |
4176 | 0 | // Check for and process any available updates |
4177 | 0 | nsCOMPtr<nsIFile> updRoot; |
4178 | 0 | bool persistent; |
4179 | 0 | rv = mDirProvider.GetFile(XRE_UPDATE_ROOT_DIR, &persistent, |
4180 | 0 | getter_AddRefs(updRoot)); |
4181 | 0 | // XRE_UPDATE_ROOT_DIR may fail. Fallback to appDir if failed |
4182 | 0 | if (NS_FAILED(rv)) |
4183 | 0 | updRoot = mDirProvider.GetAppDir(); |
4184 | 0 |
|
4185 | 0 | // If the MOZ_TEST_PROCESS_UPDATES environment variable already exists, then |
4186 | 0 | // we are being called from the callback application. |
4187 | 0 | if (EnvHasValue("MOZ_TEST_PROCESS_UPDATES")) { |
4188 | 0 | // If the caller has asked us to log our arguments, do so. This is used |
4189 | 0 | // to make sure that the maintenance service successfully launches the |
4190 | 0 | // callback application. |
4191 | 0 | const char *logFile = nullptr; |
4192 | 0 | if (ARG_FOUND == CheckArg("dump-args", &logFile)) { |
4193 | 0 | FILE* logFP = fopen(logFile, "wb"); |
4194 | 0 | if (logFP) { |
4195 | 0 | for (int i = 1; i < gRestartArgc; ++i) { |
4196 | 0 | fprintf(logFP, "%s\n", gRestartArgv[i]); |
4197 | 0 | } |
4198 | 0 | fclose(logFP); |
4199 | 0 | } |
4200 | 0 | } |
4201 | 0 | *aExitFlag = true; |
4202 | 0 | return 0; |
4203 | 0 | } |
4204 | 0 |
|
4205 | 0 | // Support for processing an update and exiting. The MOZ_TEST_PROCESS_UPDATES |
4206 | 0 | // environment variable will be part of the updater's environment and the |
4207 | 0 | // application that is relaunched by the updater. When the application is |
4208 | 0 | // relaunched by the updater it will be removed below and the application |
4209 | 0 | // will exit. |
4210 | 0 | if (CheckArg("test-process-updates")) { |
4211 | 0 | SaveToEnv("MOZ_TEST_PROCESS_UPDATES=1"); |
4212 | 0 | } |
4213 | 0 | nsCOMPtr<nsIFile> exeFile, exeDir; |
4214 | 0 | rv = mDirProvider.GetFile(XRE_EXECUTABLE_FILE, &persistent, |
4215 | 0 | getter_AddRefs(exeFile)); |
4216 | 0 | NS_ENSURE_SUCCESS(rv, 1); |
4217 | 0 | rv = exeFile->GetParent(getter_AddRefs(exeDir)); |
4218 | 0 | NS_ENSURE_SUCCESS(rv, 1); |
4219 | 0 | ProcessUpdates(mDirProvider.GetGREDir(), |
4220 | 0 | exeDir, |
4221 | 0 | updRoot, |
4222 | 0 | gRestartArgc, |
4223 | 0 | gRestartArgv, |
4224 | 0 | mAppData->version); |
4225 | 0 | if (EnvHasValue("MOZ_TEST_PROCESS_UPDATES")) { |
4226 | 0 | SaveToEnv("MOZ_TEST_PROCESS_UPDATES="); |
4227 | 0 | *aExitFlag = true; |
4228 | 0 | return 0; |
4229 | 0 | } |
4230 | 0 | #endif |
4231 | 0 | |
4232 | 0 | rv = NS_NewToolkitProfileService(getter_AddRefs(mProfileSvc)); |
4233 | 0 | if (rv == NS_ERROR_FILE_ACCESS_DENIED) { |
4234 | 0 | PR_fprintf(PR_STDERR, "Error: Access was denied while trying to open files in " \ |
4235 | 0 | "your profile directory.\n"); |
4236 | 0 | } |
4237 | 0 | if (NS_FAILED(rv)) { |
4238 | 0 | // We failed to choose or create profile - notify user and quit |
4239 | 0 | ProfileMissingDialog(mNativeApp); |
4240 | 0 | return 1; |
4241 | 0 | } |
4242 | 0 | |
4243 | 0 | rv = SelectProfile(getter_AddRefs(mProfileLock), mProfileSvc, mNativeApp, &mStartOffline, |
4244 | 0 | &mProfileName); |
4245 | 0 | if (rv == NS_ERROR_LAUNCHED_CHILD_PROCESS || |
4246 | 0 | rv == NS_ERROR_ABORT) { |
4247 | 0 | *aExitFlag = true; |
4248 | 0 | return 0; |
4249 | 0 | } |
4250 | 0 | |
4251 | 0 | if (NS_FAILED(rv)) { |
4252 | 0 | // We failed to choose or create profile - notify user and quit |
4253 | 0 | ProfileMissingDialog(mNativeApp); |
4254 | 0 | return 1; |
4255 | 0 | } |
4256 | 0 | gProfileLock = mProfileLock; |
4257 | 0 |
|
4258 | 0 | rv = mProfileLock->GetDirectory(getter_AddRefs(mProfD)); |
4259 | 0 | NS_ENSURE_SUCCESS(rv, 1); |
4260 | 0 |
|
4261 | 0 | rv = mProfileLock->GetLocalDirectory(getter_AddRefs(mProfLD)); |
4262 | 0 | NS_ENSURE_SUCCESS(rv, 1); |
4263 | 0 |
|
4264 | 0 | rv = mDirProvider.SetProfile(mProfD, mProfLD); |
4265 | 0 | NS_ENSURE_SUCCESS(rv, 1); |
4266 | 0 |
|
4267 | 0 | //////////////////////// NOW WE HAVE A PROFILE //////////////////////// |
4268 | 0 |
|
4269 | 0 | mozilla::Telemetry::SetProfileDir(mProfD); |
4270 | 0 |
|
4271 | 0 | if (mAppData->flags & NS_XRE_ENABLE_CRASH_REPORTER) |
4272 | 0 | MakeOrSetMinidumpPath(mProfD); |
4273 | 0 |
|
4274 | 0 | CrashReporter::SetProfileDirectory(mProfD); |
4275 | 0 |
|
4276 | | #ifdef MOZ_ASAN_REPORTER |
4277 | | // In ASan reporter builds, we need to set ASan's log_path as early as |
4278 | | // possible, so it dumps its errors into files there instead of using |
4279 | | // the default stderr location. Since this is crucial for ASan reporter |
4280 | | // to work at all (and we don't want people to use a non-functional |
4281 | | // ASan reporter build), all failures while setting log_path are fatal. |
4282 | | setASanReporterPath(mProfD); |
4283 | | |
4284 | | // Export to env for child processes |
4285 | | SaveFileToEnv("ASAN_REPORTER_PATH", mProfD); |
4286 | | #endif |
4287 | |
|
4288 | 0 | nsAutoCString version; |
4289 | 0 | BuildVersion(version); |
4290 | 0 |
|
4291 | 0 | #ifdef TARGET_OS_ABI |
4292 | 0 | NS_NAMED_LITERAL_CSTRING(osABI, TARGET_OS_ABI); |
4293 | | #else |
4294 | | // No TARGET_XPCOM_ABI, but at least the OS is known |
4295 | | NS_NAMED_LITERAL_CSTRING(osABI, OS_TARGET "_UNKNOWN"); |
4296 | | #endif |
4297 | |
|
4298 | 0 | // Check for version compatibility with the last version of the app this |
4299 | 0 | // profile was started with. The format of the version stamp is defined |
4300 | 0 | // by the BuildVersion function. |
4301 | 0 | // Also check to see if something has happened to invalidate our |
4302 | 0 | // fastload caches, like an extension upgrade or installation. |
4303 | 0 |
|
4304 | 0 | // If we see .purgecaches, that means someone did a make. |
4305 | 0 | // Re-register components to catch potential changes. |
4306 | 0 | nsCOMPtr<nsIFile> flagFile; |
4307 | 0 | if (mAppData->directory) { |
4308 | 0 | Unused << mAppData->directory->Clone(getter_AddRefs(flagFile)); |
4309 | 0 | } |
4310 | 0 | if (flagFile) { |
4311 | 0 | flagFile->AppendNative(FILE_INVALIDATE_CACHES); |
4312 | 0 | } |
4313 | 0 |
|
4314 | 0 | bool cachesOK; |
4315 | 0 | bool versionOK = CheckCompatibility(mProfD, version, osABI, |
4316 | 0 | mDirProvider.GetGREDir(), |
4317 | 0 | mAppData->directory, flagFile, |
4318 | 0 | &cachesOK); |
4319 | 0 |
|
4320 | 0 | bool lastStartupWasCrash = CheckLastStartupWasCrash().unwrapOr(false); |
4321 | 0 |
|
4322 | 0 | if (CheckArg("purgecaches") || PR_GetEnv("MOZ_PURGE_CACHES") || |
4323 | 0 | lastStartupWasCrash) { |
4324 | 0 | cachesOK = false; |
4325 | 0 | } |
4326 | 0 |
|
4327 | 0 | // Every time a profile is loaded by a build with a different version, |
4328 | 0 | // it updates the compatibility.ini file saying what version last wrote |
4329 | 0 | // the fastload caches. On subsequent launches if the version matches, |
4330 | 0 | // there is no need for re-registration. If the user loads the same |
4331 | 0 | // profile in different builds the component registry must be |
4332 | 0 | // re-generated to prevent mysterious component loading failures. |
4333 | 0 | // |
4334 | 0 | bool startupCacheValid = true; |
4335 | 0 | if (gSafeMode) { |
4336 | 0 | startupCacheValid = RemoveComponentRegistries(mProfD, mProfLD, false); |
4337 | 0 | WriteVersion(mProfD, NS_LITERAL_CSTRING("Safe Mode"), osABI, |
4338 | 0 | mDirProvider.GetGREDir(), mAppData->directory, !startupCacheValid); |
4339 | 0 | } |
4340 | 0 | else if (versionOK) { |
4341 | 0 | if (!cachesOK) { |
4342 | 0 | // Remove caches, forcing component re-registration. |
4343 | 0 | // The new list of additional components directories is derived from |
4344 | 0 | // information in "extensions.ini". |
4345 | 0 | startupCacheValid = RemoveComponentRegistries(mProfD, mProfLD, false); |
4346 | 0 |
|
4347 | 0 | // Rewrite compatibility.ini to remove the flag |
4348 | 0 | WriteVersion(mProfD, version, osABI, |
4349 | 0 | mDirProvider.GetGREDir(), mAppData->directory, !startupCacheValid); |
4350 | 0 | } |
4351 | 0 | // Nothing need be done for the normal startup case. |
4352 | 0 | } |
4353 | 0 | else { |
4354 | 0 | // Remove caches, forcing component re-registration |
4355 | 0 | // with the default set of components (this disables any potentially |
4356 | 0 | // troublesome incompatible XPCOM components). |
4357 | 0 | startupCacheValid = RemoveComponentRegistries(mProfD, mProfLD, true); |
4358 | 0 |
|
4359 | 0 | // Write out version |
4360 | 0 | WriteVersion(mProfD, version, osABI, |
4361 | 0 | mDirProvider.GetGREDir(), mAppData->directory, !startupCacheValid); |
4362 | 0 | } |
4363 | 0 |
|
4364 | 0 | if (!startupCacheValid) |
4365 | 0 | StartupCache::IgnoreDiskCache(); |
4366 | 0 |
|
4367 | 0 | if (flagFile) { |
4368 | 0 | flagFile->Remove(true); |
4369 | 0 | } |
4370 | 0 |
|
4371 | 0 | return 0; |
4372 | 0 | } |
4373 | | |
4374 | | #if defined(MOZ_CONTENT_SANDBOX) |
4375 | | void AddSandboxAnnotations() |
4376 | 0 | { |
4377 | 0 | // Include the sandbox content level, regardless of platform |
4378 | 0 | int level = GetEffectiveContentSandboxLevel(); |
4379 | 0 |
|
4380 | 0 | nsAutoCString levelString; |
4381 | 0 | levelString.AppendInt(level); |
4382 | 0 |
|
4383 | 0 | CrashReporter::AnnotateCrashReport( |
4384 | 0 | CrashReporter::Annotation::ContentSandboxLevel, levelString); |
4385 | 0 |
|
4386 | 0 | // Include whether or not this instance is capable of content sandboxing |
4387 | 0 | bool sandboxCapable = false; |
4388 | 0 |
|
4389 | | #if defined(XP_WIN) |
4390 | | // All supported Windows versions support some level of content sandboxing |
4391 | | sandboxCapable = true; |
4392 | | #elif defined(XP_MACOSX) |
4393 | | // All supported OS X versions are capable |
4394 | | sandboxCapable = true; |
4395 | | #elif defined(XP_LINUX) |
4396 | | sandboxCapable = SandboxInfo::Get().CanSandboxContent(); |
4397 | | #elif defined(__OpenBSD__) |
4398 | | sandboxCapable = true; |
4399 | | StartOpenBSDSandbox(GeckoProcessType_Default); |
4400 | | #endif |
4401 | |
|
4402 | 0 | CrashReporter::AnnotateCrashReport( |
4403 | 0 | CrashReporter::Annotation::ContentSandboxCapable, sandboxCapable); |
4404 | 0 | } |
4405 | | #endif /* MOZ_CONTENT_SANDBOX */ |
4406 | | |
4407 | | /* |
4408 | | * XRE_mainRun - Command line startup, profile migration, and |
4409 | | * the calling of appStartup->Run(). |
4410 | | */ |
4411 | | nsresult |
4412 | | XREMain::XRE_mainRun() |
4413 | 0 | { |
4414 | 0 | nsresult rv = NS_OK; |
4415 | 0 | NS_ASSERTION(mScopedXPCOM, "Scoped xpcom not initialized."); |
4416 | 0 |
|
4417 | | #if defined(XP_WIN) |
4418 | | RefPtr<mozilla::DllServices> dllServices(mozilla::DllServices::Get()); |
4419 | | auto dllServicesDisable = MakeScopeExit([&dllServices]() { |
4420 | | dllServices->Disable(); |
4421 | | }); |
4422 | | #endif // defined(XP_WIN) |
4423 | |
|
4424 | | #ifdef NS_FUNCTION_TIMER |
4425 | | // initialize some common services, so we don't pay the cost for these at odd times later on; |
4426 | | // SetWindowCreator -> ChromeRegistry -> IOService -> SocketTransportService -> (nspr wspm init), Prefs |
4427 | | { |
4428 | | nsCOMPtr<nsISupports> comp; |
4429 | | |
4430 | | comp = do_GetService("@mozilla.org/preferences-service;1"); |
4431 | | |
4432 | | comp = do_GetService("@mozilla.org/network/socket-transport-service;1"); |
4433 | | |
4434 | | comp = do_GetService("@mozilla.org/network/dns-service;1"); |
4435 | | |
4436 | | comp = do_GetService("@mozilla.org/network/io-service;1"); |
4437 | | |
4438 | | comp = do_GetService("@mozilla.org/chrome/chrome-registry;1"); |
4439 | | |
4440 | | comp = do_GetService("@mozilla.org/focus-event-suppressor-service;1"); |
4441 | | } |
4442 | | #endif |
4443 | |
|
4444 | 0 | rv = mScopedXPCOM->SetWindowCreator(mNativeApp); |
4445 | 0 | NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); |
4446 | 0 |
|
4447 | 0 | // tell the crash reporter to also send the release channel |
4448 | 0 | nsCOMPtr<nsIPrefService> prefs = do_GetService("@mozilla.org/preferences-service;1", &rv); |
4449 | 0 | if (NS_SUCCEEDED(rv)) { |
4450 | 0 | nsCOMPtr<nsIPrefBranch> defaultPrefBranch; |
4451 | 0 | rv = prefs->GetDefaultBranch(nullptr, getter_AddRefs(defaultPrefBranch)); |
4452 | 0 |
|
4453 | 0 | if (NS_SUCCEEDED(rv)) { |
4454 | 0 | nsAutoCString sval; |
4455 | 0 | rv = defaultPrefBranch->GetCharPref("app.update.channel", sval); |
4456 | 0 | if (NS_SUCCEEDED(rv)) { |
4457 | 0 | CrashReporter::AnnotateCrashReport( |
4458 | 0 | CrashReporter::Annotation::ReleaseChannel, sval); |
4459 | 0 | } |
4460 | 0 | } |
4461 | 0 | } |
4462 | 0 | // Needs to be set after xpcom initialization. |
4463 | 0 | CrashReporter::AnnotateCrashReport( |
4464 | 0 | CrashReporter::Annotation::FramePoisonBase, |
4465 | 0 | nsPrintfCString("%.16" PRIu64, uint64_t(gMozillaPoisonBase))); |
4466 | 0 | CrashReporter::AnnotateCrashReport( |
4467 | 0 | CrashReporter::Annotation::FramePoisonSize, |
4468 | 0 | uint32_t(gMozillaPoisonSize)); |
4469 | 0 |
|
4470 | 0 | bool includeContextHeap = |
4471 | 0 | Preferences::GetBool("toolkit.crashreporter.include_context_heap", false); |
4472 | 0 | CrashReporter::SetIncludeContextHeap(includeContextHeap); |
4473 | 0 |
|
4474 | | #ifdef XP_WIN |
4475 | | PR_CreateThread(PR_USER_THREAD, AnnotateWMIData_ThreadStart, 0, |
4476 | | PR_PRIORITY_LOW, PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD, 0); |
4477 | | #endif |
4478 | |
|
4479 | 0 | #if defined(XP_LINUX) && !defined(ANDROID) |
4480 | 0 | PR_CreateThread(PR_USER_THREAD, AnnotateLSBRelease, 0, PR_PRIORITY_LOW, |
4481 | 0 | PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD, 0); |
4482 | 0 | #endif |
4483 | 0 |
|
4484 | 0 | if (mStartOffline) { |
4485 | 0 | nsCOMPtr<nsIIOService> io(do_GetService("@mozilla.org/network/io-service;1")); |
4486 | 0 | NS_ENSURE_TRUE(io, NS_ERROR_FAILURE); |
4487 | 0 | io->SetManageOfflineStatus(false); |
4488 | 0 | io->SetOffline(true); |
4489 | 0 | } |
4490 | 0 |
|
4491 | 0 |
|
4492 | | #ifdef XP_WIN |
4493 | | if (!PR_GetEnv("XRE_NO_DLL_READAHEAD")) |
4494 | | { |
4495 | | PR_CreateThread(PR_USER_THREAD, ReadAheadDlls_ThreadStart, 0, |
4496 | | PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, |
4497 | | PR_UNJOINABLE_THREAD, 0); |
4498 | | } |
4499 | | #endif |
4500 | |
|
4501 | 0 | if (gDoMigration) { |
4502 | 0 | nsCOMPtr<nsIFile> file; |
4503 | 0 | mDirProvider.GetAppDir()->Clone(getter_AddRefs(file)); |
4504 | 0 | file->AppendNative(NS_LITERAL_CSTRING("override.ini")); |
4505 | 0 | nsINIParser parser; |
4506 | 0 | nsresult rv = parser.Init(file); |
4507 | 0 | // if override.ini doesn't exist, also check for distribution.ini |
4508 | 0 | if (NS_FAILED(rv)) { |
4509 | 0 | bool persistent; |
4510 | 0 | mDirProvider.GetFile(XRE_APP_DISTRIBUTION_DIR, &persistent, |
4511 | 0 | getter_AddRefs(file)); |
4512 | 0 | file->AppendNative(NS_LITERAL_CSTRING("distribution.ini")); |
4513 | 0 | rv = parser.Init(file); |
4514 | 0 | } |
4515 | 0 | if (NS_SUCCEEDED(rv)) { |
4516 | 0 | nsAutoCString buf; |
4517 | 0 | rv = parser.GetString("XRE", "EnableProfileMigrator", buf); |
4518 | 0 | if (NS_SUCCEEDED(rv)) { |
4519 | 0 | if (buf[0] == '0' || buf[0] == 'f' || buf[0] == 'F') { |
4520 | 0 | gDoMigration = false; |
4521 | 0 | } |
4522 | 0 | } |
4523 | 0 | } |
4524 | 0 | } |
4525 | 0 |
|
4526 | 0 | { |
4527 | 0 | nsCOMPtr<nsIToolkitProfile> profileBeingReset; |
4528 | 0 | bool profileWasSelected = false; |
4529 | 0 | if (gDoProfileReset) { |
4530 | 0 | if (gResetOldProfileName.IsEmpty()) { |
4531 | 0 | NS_WARNING("Not resetting profile as the profile has no name."); |
4532 | 0 | gDoProfileReset = false; |
4533 | 0 | } else { |
4534 | 0 | rv = mProfileSvc->GetProfileByName(gResetOldProfileName, |
4535 | 0 | getter_AddRefs(profileBeingReset)); |
4536 | 0 | if (NS_FAILED(rv)) { |
4537 | 0 | gDoProfileReset = false; |
4538 | 0 | return NS_ERROR_FAILURE; |
4539 | 0 | } |
4540 | 0 | |
4541 | 0 | nsCOMPtr<nsIToolkitProfile> defaultProfile; |
4542 | 0 | // This can fail if there is no default profile. |
4543 | 0 | // That shouldn't stop reset from proceeding. |
4544 | 0 | nsresult gotSelected = mProfileSvc->GetSelectedProfile(getter_AddRefs(defaultProfile)); |
4545 | 0 | if (NS_SUCCEEDED(gotSelected)) { |
4546 | 0 | profileWasSelected = defaultProfile == profileBeingReset; |
4547 | 0 | } |
4548 | 0 | } |
4549 | 0 | } |
4550 | 0 |
|
4551 | 0 | // Profile Migration |
4552 | 0 | if (mAppData->flags & NS_XRE_ENABLE_PROFILE_MIGRATOR && gDoMigration) { |
4553 | 0 | gDoMigration = false; |
4554 | 0 | nsCOMPtr<nsIProfileMigrator> pm(do_CreateInstance(NS_PROFILEMIGRATOR_CONTRACTID)); |
4555 | 0 | if (pm) { |
4556 | 0 | nsAutoCString aKey; |
4557 | 0 | if (gDoProfileReset) { |
4558 | 0 | // Automatically migrate from the current application if we just |
4559 | 0 | // reset the profile. |
4560 | 0 | aKey = MOZ_APP_NAME; |
4561 | 0 | } |
4562 | 0 | pm->Migrate(&mDirProvider, aKey, gResetOldProfileName); |
4563 | 0 | } |
4564 | 0 | } |
4565 | 0 |
|
4566 | 0 | if (gDoProfileReset) { |
4567 | 0 | nsresult backupCreated = ProfileResetCleanup(profileBeingReset); |
4568 | 0 | if (NS_FAILED(backupCreated)) NS_WARNING("Could not cleanup the profile that was reset"); |
4569 | 0 |
|
4570 | 0 | nsCOMPtr<nsIToolkitProfile> newProfile; |
4571 | 0 | rv = GetCurrentProfile(mProfileSvc, mProfD, getter_AddRefs(newProfile)); |
4572 | 0 | if (NS_SUCCEEDED(rv)) { |
4573 | 0 | newProfile->SetName(gResetOldProfileName); |
4574 | 0 | mProfileName.Assign(gResetOldProfileName); |
4575 | 0 | // Set the new profile as the default after we're done cleaning up the old profile, |
4576 | 0 | // iff that profile was already the default |
4577 | 0 | if (profileWasSelected) { |
4578 | 0 | rv = mProfileSvc->SetDefaultProfile(newProfile); |
4579 | 0 | if (NS_FAILED(rv)) NS_WARNING("Could not set current profile as the default"); |
4580 | 0 | } |
4581 | 0 | } else { |
4582 | 0 | NS_WARNING("Could not find current profile to set as default / change name."); |
4583 | 0 | } |
4584 | 0 |
|
4585 | 0 | // Need to write out the fact that the profile has been removed, the new profile |
4586 | 0 | // renamed, and potentially that the selected/default profile changed. |
4587 | 0 | mProfileSvc->Flush(); |
4588 | 0 | } |
4589 | 0 | } |
4590 | 0 |
|
4591 | 0 | #ifndef XP_WIN |
4592 | 0 | nsCOMPtr<nsIFile> profileDir; |
4593 | 0 | nsAutoCString path; |
4594 | 0 | rv = mDirProvider.GetProfileStartupDir(getter_AddRefs(profileDir)); |
4595 | 0 | if (NS_SUCCEEDED(rv) && NS_SUCCEEDED(profileDir->GetNativePath(path)) && !IsUTF8(path)) { |
4596 | 0 | PR_fprintf(PR_STDERR, "Error: The profile path is not valid UTF-8. Unable to continue.\n"); |
4597 | 0 | return NS_ERROR_FAILURE; |
4598 | 0 | } |
4599 | 0 | #endif |
4600 | 0 | |
4601 | 0 | // Initialize user preferences before notifying startup observers so they're |
4602 | 0 | // ready in time for early consumers, such as the component loader. |
4603 | 0 | mDirProvider.InitializeUserPrefs(); |
4604 | 0 |
|
4605 | 0 | nsAppStartupNotifier::NotifyObservers(APPSTARTUP_TOPIC); |
4606 | 0 |
|
4607 | 0 | nsCOMPtr<nsIAppStartup> appStartup |
4608 | 0 | (do_GetService(NS_APPSTARTUP_CONTRACTID)); |
4609 | 0 | NS_ENSURE_TRUE(appStartup, NS_ERROR_FAILURE); |
4610 | 0 |
|
4611 | 0 | mDirProvider.DoStartup(); |
4612 | 0 |
|
4613 | 0 | // As FilePreferences need the profile directory, we must initialize right here. |
4614 | 0 | mozilla::FilePreferences::InitDirectoriesWhitelist(); |
4615 | 0 | mozilla::FilePreferences::InitPrefs(); |
4616 | 0 |
|
4617 | 0 | OverrideDefaultLocaleIfNeeded(); |
4618 | 0 |
|
4619 | 0 | nsCString userAgentLocale; |
4620 | 0 | LocaleService::GetInstance()->GetAppLocaleAsLangTag(userAgentLocale); |
4621 | 0 | CrashReporter::AnnotateCrashReport( |
4622 | 0 | CrashReporter::Annotation::useragent_locale, userAgentLocale); |
4623 | 0 |
|
4624 | 0 | appStartup->GetShuttingDown(&mShuttingDown); |
4625 | 0 |
|
4626 | 0 | nsCOMPtr<nsICommandLineRunner> cmdLine; |
4627 | 0 |
|
4628 | 0 | nsCOMPtr<nsIFile> workingDir; |
4629 | 0 | rv = NS_GetSpecialDirectory(NS_OS_CURRENT_WORKING_DIR, getter_AddRefs(workingDir)); |
4630 | 0 | NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); |
4631 | 0 |
|
4632 | 0 | if (!mShuttingDown) { |
4633 | 0 | cmdLine = new nsCommandLine(); |
4634 | 0 |
|
4635 | 0 | rv = cmdLine->Init(gArgc, gArgv, workingDir, |
4636 | 0 | nsICommandLine::STATE_INITIAL_LAUNCH); |
4637 | 0 | NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); |
4638 | 0 |
|
4639 | 0 | /* Special-case services that need early access to the command |
4640 | 0 | line. */ |
4641 | 0 | nsCOMPtr<nsIObserverService> obsService = |
4642 | 0 | mozilla::services::GetObserverService(); |
4643 | 0 | if (obsService) { |
4644 | 0 | obsService->NotifyObservers(cmdLine, "command-line-startup", nullptr); |
4645 | 0 | } |
4646 | 0 | } |
4647 | 0 |
|
4648 | | #ifdef XP_WIN |
4649 | | // Hack to sync up the various environment storages. XUL_APP_FILE is special |
4650 | | // in that it comes from a different CRT (firefox.exe's static-linked copy). |
4651 | | // Ugly details in http://bugzil.la/1175039#c27 |
4652 | | char appFile[MAX_PATH]; |
4653 | | if (GetEnvironmentVariableA("XUL_APP_FILE", appFile, sizeof(appFile))) { |
4654 | | SmprintfPointer saved = mozilla::Smprintf("XUL_APP_FILE=%s", appFile); |
4655 | | // We intentionally leak the string here since it is required by PR_SetEnv. |
4656 | | PR_SetEnv(saved.release()); |
4657 | | } |
4658 | | |
4659 | | #if defined(MOZ_SANDBOX) |
4660 | | // Call SandboxBroker to initialize things that depend on Gecko machinery like |
4661 | | // the directory provider. |
4662 | | SandboxBroker::GeckoDependentInitialize(); |
4663 | | #endif |
4664 | | #endif |
4665 | |
|
4666 | 0 | SaveStateForAppInitiatedRestart(); |
4667 | 0 |
|
4668 | 0 | // clear out any environment variables which may have been set |
4669 | 0 | // during the relaunch process now that we know we won't be relaunching. |
4670 | 0 | SaveToEnv("XRE_PROFILE_PATH="); |
4671 | 0 | SaveToEnv("XRE_PROFILE_LOCAL_PATH="); |
4672 | 0 | SaveToEnv("XRE_PROFILE_NAME="); |
4673 | 0 | SaveToEnv("XRE_START_OFFLINE="); |
4674 | 0 | SaveToEnv("XUL_APP_FILE="); |
4675 | 0 | SaveToEnv("XRE_BINARY_PATH="); |
4676 | 0 |
|
4677 | 0 | if (!mShuttingDown) { |
4678 | 0 | rv = appStartup->CreateHiddenWindow(); |
4679 | 0 | NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); |
4680 | 0 |
|
4681 | | #ifdef XP_WIN |
4682 | | Preferences::RegisterCallbackAndCall(RegisterApplicationRestartChanged, |
4683 | | PREF_WIN_REGISTER_APPLICATION_RESTART); |
4684 | | #endif |
4685 | |
|
4686 | 0 | #if defined(HAVE_DESKTOP_STARTUP_ID) && defined(MOZ_WIDGET_GTK) |
4687 | 0 | nsGTKToolkit* toolkit = nsGTKToolkit::GetToolkit(); |
4688 | 0 | if (toolkit && !mDesktopStartupID.IsEmpty()) { |
4689 | 0 | toolkit->SetDesktopStartupID(mDesktopStartupID); |
4690 | 0 | } |
4691 | 0 | // Clear the environment variable so it won't be inherited by |
4692 | 0 | // child processes and confuse things. |
4693 | 0 | g_unsetenv ("DESKTOP_STARTUP_ID"); |
4694 | 0 | #endif |
4695 | 0 |
|
4696 | | #ifdef XP_MACOSX |
4697 | | // we re-initialize the command-line service and do appleevents munging |
4698 | | // after we are sure that we're not restarting |
4699 | | cmdLine = new nsCommandLine(); |
4700 | | |
4701 | | CommandLineServiceMac::SetupMacCommandLine(gArgc, gArgv, false); |
4702 | | |
4703 | | rv = cmdLine->Init(gArgc, gArgv, |
4704 | | workingDir, nsICommandLine::STATE_INITIAL_LAUNCH); |
4705 | | NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); |
4706 | | #endif |
4707 | |
|
4708 | 0 | nsCOMPtr<nsIObserverService> obsService = |
4709 | 0 | mozilla::services::GetObserverService(); |
4710 | 0 | if (obsService) |
4711 | 0 | obsService->NotifyObservers(nullptr, "final-ui-startup", nullptr); |
4712 | 0 |
|
4713 | 0 | (void)appStartup->DoneStartingUp(); |
4714 | 0 |
|
4715 | 0 | CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::StartupCrash, |
4716 | 0 | false); |
4717 | 0 |
|
4718 | 0 | appStartup->GetShuttingDown(&mShuttingDown); |
4719 | 0 | } |
4720 | 0 |
|
4721 | 0 | if (!mShuttingDown) { |
4722 | 0 | rv = cmdLine->Run(); |
4723 | 0 | NS_ENSURE_SUCCESS_LOG(rv, NS_ERROR_FAILURE); |
4724 | 0 |
|
4725 | 0 | appStartup->GetShuttingDown(&mShuttingDown); |
4726 | 0 | } |
4727 | 0 |
|
4728 | 0 | if (!mShuttingDown) { |
4729 | 0 | #ifdef MOZ_ENABLE_XREMOTE |
4730 | 0 | // if we have X remote support, start listening for requests on the |
4731 | 0 | // proxy window. |
4732 | 0 | if (!mDisableRemote) |
4733 | 0 | mRemoteService = do_GetService("@mozilla.org/toolkit/remote-service;1"); |
4734 | 0 | if (mRemoteService) |
4735 | 0 | mRemoteService->Startup(mAppData->remotingName, mProfileName.get()); |
4736 | 0 | if (mRemoteLockDir) { |
4737 | 0 | mRemoteLock.Unlock(); |
4738 | 0 | mRemoteLock.Cleanup(); |
4739 | 0 | mRemoteLockDir->Remove(false); |
4740 | 0 | } |
4741 | 0 | #endif /* MOZ_ENABLE_XREMOTE */ |
4742 | 0 |
|
4743 | 0 | mNativeApp->Enable(); |
4744 | 0 | } |
4745 | 0 |
|
4746 | 0 | #ifdef MOZ_INSTRUMENT_EVENT_LOOP |
4747 | 0 | if (PR_GetEnv("MOZ_INSTRUMENT_EVENT_LOOP")) { |
4748 | 0 | bool logToConsole = true; |
4749 | 0 | mozilla::InitEventTracing(logToConsole); |
4750 | 0 | } |
4751 | 0 | #endif /* MOZ_INSTRUMENT_EVENT_LOOP */ |
4752 | 0 |
|
4753 | 0 | #if defined(MOZ_SANDBOX) && defined(XP_LINUX) |
4754 | 0 | // If we're on Linux, we now have information about the OS capabilities |
4755 | 0 | // available to us. |
4756 | 0 | SandboxInfo sandboxInfo = SandboxInfo::Get(); |
4757 | 0 | Telemetry::Accumulate(Telemetry::SANDBOX_HAS_SECCOMP_BPF, |
4758 | 0 | sandboxInfo.Test(SandboxInfo::kHasSeccompBPF)); |
4759 | 0 | Telemetry::Accumulate(Telemetry::SANDBOX_HAS_SECCOMP_TSYNC, |
4760 | 0 | sandboxInfo.Test(SandboxInfo::kHasSeccompTSync)); |
4761 | 0 | Telemetry::Accumulate(Telemetry::SANDBOX_HAS_USER_NAMESPACES_PRIVILEGED, |
4762 | 0 | sandboxInfo.Test(SandboxInfo::kHasPrivilegedUserNamespaces)); |
4763 | 0 | Telemetry::Accumulate(Telemetry::SANDBOX_HAS_USER_NAMESPACES, |
4764 | 0 | sandboxInfo.Test(SandboxInfo::kHasUserNamespaces)); |
4765 | 0 | Telemetry::Accumulate(Telemetry::SANDBOX_CONTENT_ENABLED, |
4766 | 0 | sandboxInfo.Test(SandboxInfo::kEnabledForContent)); |
4767 | 0 | Telemetry::Accumulate(Telemetry::SANDBOX_MEDIA_ENABLED, |
4768 | 0 | sandboxInfo.Test(SandboxInfo::kEnabledForMedia)); |
4769 | 0 | nsAutoCString flagsString; |
4770 | 0 | flagsString.AppendInt(sandboxInfo.AsInteger()); |
4771 | 0 |
|
4772 | 0 | CrashReporter::AnnotateCrashReport( |
4773 | 0 | CrashReporter::Annotation::ContentSandboxCapabilities, flagsString); |
4774 | 0 | #endif /* MOZ_SANDBOX && XP_LINUX */ |
4775 | 0 |
|
4776 | 0 | #if defined(MOZ_CONTENT_SANDBOX) |
4777 | 0 | AddSandboxAnnotations(); |
4778 | 0 | #endif /* MOZ_CONTENT_SANDBOX */ |
4779 | 0 |
|
4780 | 0 | { |
4781 | 0 | rv = appStartup->Run(); |
4782 | 0 | if (NS_FAILED(rv)) { |
4783 | 0 | NS_ERROR("failed to run appstartup"); |
4784 | 0 | gLogConsoleErrors = true; |
4785 | 0 | } |
4786 | 0 | } |
4787 | 0 |
|
4788 | 0 | return rv; |
4789 | 0 | } |
4790 | | |
4791 | | /* |
4792 | | * XRE_main - A class based main entry point used by most platforms. |
4793 | | * Note that on OSX, aAppData->xreDirectory will point to |
4794 | | * .app/Contents/Resources. |
4795 | | */ |
4796 | | int |
4797 | | XREMain::XRE_main(int argc, char* argv[], const BootstrapConfig& aConfig) |
4798 | 3 | { |
4799 | 3 | ScopedLogging log; |
4800 | 3 | |
4801 | 3 | mozilla::LogModule::Init(argc, argv); |
4802 | 3 | |
4803 | | #ifdef MOZ_CODE_COVERAGE |
4804 | | CodeCoverageHandler::Init(); |
4805 | | #endif |
4806 | | |
4807 | 3 | AUTO_PROFILER_INIT; |
4808 | 3 | AUTO_PROFILER_LABEL("XREMain::XRE_main", OTHER); |
4809 | 3 | |
4810 | 3 | nsresult rv = NS_OK; |
4811 | 3 | |
4812 | 3 | gArgc = argc; |
4813 | 3 | gArgv = argv; |
4814 | 3 | |
4815 | 3 | if (aConfig.appData) { |
4816 | 3 | mAppData = MakeUnique<XREAppData>(*aConfig.appData); |
4817 | 3 | } else { |
4818 | 0 | MOZ_RELEASE_ASSERT(aConfig.appDataPath); |
4819 | 0 | nsCOMPtr<nsIFile> appini; |
4820 | 0 | rv = XRE_GetFileFromPath(aConfig.appDataPath, getter_AddRefs(appini)); |
4821 | 0 | if (NS_FAILED(rv)) { |
4822 | 0 | Output(true, "Error: unrecognized path: %s\n", aConfig.appDataPath); |
4823 | 0 | return 1; |
4824 | 0 | } |
4825 | 0 | |
4826 | 0 | mAppData = MakeUnique<XREAppData>(); |
4827 | 0 | rv = XRE_ParseAppData(appini, *mAppData); |
4828 | 0 | if (NS_FAILED(rv)) { |
4829 | 0 | Output(true, "Couldn't read application.ini"); |
4830 | 0 | return 1; |
4831 | 0 | } |
4832 | 0 | |
4833 | 0 | appini->GetParent(getter_AddRefs(mAppData->directory)); |
4834 | 0 | } |
4835 | 3 | |
4836 | 3 | if (!mAppData->remotingName) { |
4837 | 0 | mAppData->remotingName = mAppData->name; |
4838 | 0 | } |
4839 | 3 | // used throughout this file |
4840 | 3 | gAppData = mAppData.get(); |
4841 | 3 | |
4842 | 3 | nsCOMPtr<nsIFile> binFile; |
4843 | 3 | rv = XRE_GetBinaryPath(getter_AddRefs(binFile)); |
4844 | 3 | NS_ENSURE_SUCCESS(rv, 1); |
4845 | 3 | |
4846 | 3 | rv = binFile->GetPath(gAbsoluteArgv0Path); |
4847 | 3 | NS_ENSURE_SUCCESS(rv, 1); |
4848 | 3 | |
4849 | 3 | if (!mAppData->xreDirectory) { |
4850 | 3 | nsCOMPtr<nsIFile> lf; |
4851 | 3 | rv = XRE_GetBinaryPath(getter_AddRefs(lf)); |
4852 | 3 | if (NS_FAILED(rv)) |
4853 | 3 | return 2; |
4854 | 3 | |
4855 | 3 | nsCOMPtr<nsIFile> greDir; |
4856 | 3 | rv = lf->GetParent(getter_AddRefs(greDir)); |
4857 | 3 | if (NS_FAILED(rv)) |
4858 | 3 | return 2; |
4859 | 3 | |
4860 | | #ifdef XP_MACOSX |
4861 | | nsCOMPtr<nsIFile> parent; |
4862 | | greDir->GetParent(getter_AddRefs(parent)); |
4863 | | greDir = parent.forget(); |
4864 | | greDir->AppendNative(NS_LITERAL_CSTRING("Resources")); |
4865 | | #endif |
4866 | | |
4867 | 3 | mAppData->xreDirectory = greDir; |
4868 | 3 | } |
4869 | 3 | |
4870 | 3 | if (aConfig.appData && aConfig.appDataPath) { |
4871 | 3 | mAppData->xreDirectory->Clone(getter_AddRefs(mAppData->directory)); |
4872 | 3 | mAppData->directory->AppendNative(nsDependentCString(aConfig.appDataPath)); |
4873 | 3 | } |
4874 | 3 | |
4875 | 3 | if (!mAppData->directory) { |
4876 | 0 | mAppData->directory = mAppData->xreDirectory; |
4877 | 0 | } |
4878 | 3 | |
4879 | | #if defined(XP_WIN) && defined(MOZ_SANDBOX) |
4880 | | mAppData->sandboxBrokerServices = aConfig.sandboxBrokerServices; |
4881 | | mAppData->sandboxPermissionsService = aConfig.sandboxPermissionsService; |
4882 | | #endif |
4883 | | |
4884 | 3 | mozilla::IOInterposerInit ioInterposerGuard; |
4885 | 3 | |
4886 | | #if defined(XP_WIN) |
4887 | | // Some COM settings are global to the process and must be set before any non- |
4888 | | // trivial COM is run in the application. Since these settings may affect |
4889 | | // stability, we should instantiate COM ASAP so that we can ensure that these |
4890 | | // global settings are configured before anything can interfere. |
4891 | | mozilla::mscom::MainThreadRuntime msCOMRuntime; |
4892 | | #endif |
4893 | | |
4894 | 3 | // init |
4895 | 3 | bool exit = false; |
4896 | 3 | int result = XRE_mainInit(&exit); |
4897 | 3 | if (result != 0 || exit) |
4898 | 0 | return result; |
4899 | 3 | |
4900 | 3 | // If we exit gracefully, remove the startup crash canary file. |
4901 | 3 | auto cleanup = MakeScopeExit([&] () -> nsresult { |
4902 | 0 | if (mProfLD) { |
4903 | 0 | nsCOMPtr<nsIFile> crashFile; |
4904 | 0 | MOZ_TRY_VAR(crashFile, GetIncompleteStartupFile(mProfLD)); |
4905 | 0 | crashFile->Remove(false); |
4906 | 0 | } |
4907 | 0 | return NS_OK; |
4908 | 0 | }); |
4909 | 3 | |
4910 | 3 | // startup |
4911 | 3 | result = XRE_mainStartup(&exit); |
4912 | 3 | if (result != 0 || exit) |
4913 | 0 | return result; |
4914 | 3 | |
4915 | 3 | bool appInitiatedRestart = false; |
4916 | 3 | |
4917 | 3 | // Start the real application |
4918 | 3 | mScopedXPCOM = MakeUnique<ScopedXPCOMStartup>(); |
4919 | 3 | if (!mScopedXPCOM) |
4920 | 0 | return 1; |
4921 | 3 | |
4922 | 3 | rv = mScopedXPCOM->Initialize(); |
4923 | 3 | NS_ENSURE_SUCCESS(rv, 1); |
4924 | 3 | |
4925 | 3 | // run! |
4926 | 3 | rv = XRE_mainRun(); |
4927 | 3 | |
4928 | 3 | #ifdef MOZ_INSTRUMENT_EVENT_LOOP |
4929 | 3 | mozilla::ShutdownEventTracing(); |
4930 | 3 | #endif |
4931 | 3 | |
4932 | 3 | gAbsoluteArgv0Path.Truncate(); |
4933 | 3 | |
4934 | 3 | // Check for an application initiated restart. This is one that |
4935 | 3 | // corresponds to nsIAppStartup.quit(eRestart) |
4936 | 3 | if (rv == NS_SUCCESS_RESTART_APP |
4937 | 3 | || rv == NS_SUCCESS_RESTART_APP_NOT_SAME_PROFILE) { |
4938 | 0 | appInitiatedRestart = true; |
4939 | 0 |
|
4940 | 0 | // We have an application restart don't do any shutdown checks here |
4941 | 0 | // In particular we don't want to poison IO for checking late-writes. |
4942 | 0 | gShutdownChecks = SCM_NOTHING; |
4943 | 0 | } |
4944 | 3 | |
4945 | 3 | if (!mShuttingDown) { |
4946 | 0 | #ifdef MOZ_ENABLE_XREMOTE |
4947 | 0 | // shut down the x remote proxy window |
4948 | 0 | if (mRemoteService) { |
4949 | 0 | mRemoteService->Shutdown(); |
4950 | 0 | } |
4951 | 0 | #endif /* MOZ_ENABLE_XREMOTE */ |
4952 | 0 | } |
4953 | 3 | |
4954 | 3 | mScopedXPCOM = nullptr; |
4955 | 3 | |
4956 | | #if defined(XP_WIN) |
4957 | | mozilla::widget::StopAudioSession(); |
4958 | | #endif |
4959 | | |
4960 | 3 | // unlock the profile after ScopedXPCOMStartup object (xpcom) |
4961 | 3 | // has gone out of scope. see bug #386739 for more details |
4962 | 3 | mProfileLock->Unlock(); |
4963 | 3 | gProfileLock = nullptr; |
4964 | 3 | |
4965 | 3 | // Restart the app after XPCOM has been shut down cleanly. |
4966 | 3 | if (appInitiatedRestart) { |
4967 | 0 | RestoreStateForAppInitiatedRestart(); |
4968 | 0 |
|
4969 | 0 | if (rv != NS_SUCCESS_RESTART_APP_NOT_SAME_PROFILE) { |
4970 | 0 | // Ensure that these environment variables are set: |
4971 | 0 | SaveFileToEnvIfUnset("XRE_PROFILE_PATH", mProfD); |
4972 | 0 | SaveFileToEnvIfUnset("XRE_PROFILE_LOCAL_PATH", mProfLD); |
4973 | 0 | SaveWordToEnvIfUnset("XRE_PROFILE_NAME", mProfileName); |
4974 | 0 | } |
4975 | 0 |
|
4976 | 0 | #ifdef MOZ_WIDGET_GTK |
4977 | 0 | if (!gfxPlatform::IsHeadless()) { |
4978 | 0 | MOZ_gdk_display_close(mGdkDisplay); |
4979 | 0 | } |
4980 | 0 | #endif |
4981 | 0 |
|
4982 | 0 | { |
4983 | 0 | rv = LaunchChild(mNativeApp, true); |
4984 | 0 | } |
4985 | 0 |
|
4986 | 0 | if (mAppData->flags & NS_XRE_ENABLE_CRASH_REPORTER) |
4987 | 0 | CrashReporter::UnsetExceptionHandler(); |
4988 | 0 |
|
4989 | 0 | return rv == NS_ERROR_LAUNCHED_CHILD_PROCESS ? 0 : 1; |
4990 | 0 | } |
4991 | 3 | |
4992 | 3 | #ifdef MOZ_WIDGET_GTK |
4993 | 3 | // gdk_display_close also calls gdk_display_manager_set_default_display |
4994 | 3 | // appropriately when necessary. |
4995 | 3 | if (!gfxPlatform::IsHeadless()) { |
4996 | 0 | MOZ_gdk_display_close(mGdkDisplay); |
4997 | 0 | } |
4998 | 3 | #endif |
4999 | 3 | |
5000 | 3 | if (mAppData->flags & NS_XRE_ENABLE_CRASH_REPORTER) |
5001 | 3 | CrashReporter::UnsetExceptionHandler(); |
5002 | 3 | |
5003 | 3 | XRE_DeinitCommandLine(); |
5004 | 3 | |
5005 | 3 | return NS_FAILED(rv) ? 1 : 0; |
5006 | 3 | } |
5007 | | |
5008 | | void |
5009 | 0 | XRE_StopLateWriteChecks(void) { |
5010 | 0 | mozilla::StopLateWriteChecks(); |
5011 | 0 | } |
5012 | | |
5013 | | int |
5014 | | XRE_main(int argc, char* argv[], const BootstrapConfig& aConfig) |
5015 | 3 | { |
5016 | 3 | XREMain main; |
5017 | 3 | |
5018 | 3 | int result = main.XRE_main(argc, argv, aConfig); |
5019 | 3 | mozilla::RecordShutdownEndTimeStamp(); |
5020 | 3 | return result; |
5021 | 3 | } |
5022 | | |
5023 | | nsresult |
5024 | | XRE_InitCommandLine(int aArgc, char* aArgv[]) |
5025 | 3 | { |
5026 | 3 | nsresult rv = NS_OK; |
5027 | 3 | |
5028 | | #if defined(OS_WIN) |
5029 | | CommandLine::Init(aArgc, aArgv); |
5030 | | #else |
5031 | | |
5032 | 3 | // these leak on error, but that's OK: we'll just exit() |
5033 | 3 | char** canonArgs = new char*[aArgc]; |
5034 | 3 | |
5035 | 3 | // get the canonical version of the binary's path |
5036 | 3 | nsCOMPtr<nsIFile> binFile; |
5037 | 3 | rv = XRE_GetBinaryPath(getter_AddRefs(binFile)); |
5038 | 3 | if (NS_FAILED(rv)) |
5039 | 3 | return NS_ERROR_FAILURE; |
5040 | 3 | |
5041 | 3 | nsAutoCString canonBinPath; |
5042 | 3 | rv = binFile->GetNativePath(canonBinPath); |
5043 | 3 | if (NS_FAILED(rv)) |
5044 | 3 | return NS_ERROR_FAILURE; |
5045 | 3 | |
5046 | 3 | canonArgs[0] = strdup(canonBinPath.get()); |
5047 | 3 | |
5048 | 15 | for (int i = 1; i < aArgc; ++i) { |
5049 | 12 | if (aArgv[i]) { |
5050 | 12 | canonArgs[i] = strdup(aArgv[i]); |
5051 | 12 | } |
5052 | 12 | } |
5053 | 3 | |
5054 | 3 | NS_ASSERTION(!CommandLine::IsInitialized(), "Bad news!"); |
5055 | 3 | CommandLine::Init(aArgc, canonArgs); |
5056 | 3 | |
5057 | 18 | for (int i = 0; i < aArgc; ++i) |
5058 | 15 | free(canonArgs[i]); |
5059 | 3 | delete[] canonArgs; |
5060 | 3 | #endif |
5061 | 3 | |
5062 | 3 | recordreplay::parent::InitializeUIProcess(gArgc, gArgv); |
5063 | 3 | |
5064 | 3 | const char *path = nullptr; |
5065 | 3 | ArgResult ar = CheckArg("greomni", &path); |
5066 | 3 | if (ar == ARG_BAD) { |
5067 | 0 | PR_fprintf(PR_STDERR, "Error: argument --greomni requires a path argument\n"); |
5068 | 0 | return NS_ERROR_FAILURE; |
5069 | 0 | } |
5070 | 3 | |
5071 | 3 | if (!path) |
5072 | 3 | return rv; |
5073 | 0 | |
5074 | 0 | nsCOMPtr<nsIFile> greOmni; |
5075 | 0 | rv = XRE_GetFileFromPath(path, getter_AddRefs(greOmni)); |
5076 | 0 | if (NS_FAILED(rv)) { |
5077 | 0 | PR_fprintf(PR_STDERR, "Error: argument --greomni requires a valid path\n"); |
5078 | 0 | return rv; |
5079 | 0 | } |
5080 | 0 | |
5081 | 0 | ar = CheckArg("appomni", &path); |
5082 | 0 | if (ar == ARG_BAD) { |
5083 | 0 | PR_fprintf(PR_STDERR, "Error: argument --appomni requires a path argument\n"); |
5084 | 0 | return NS_ERROR_FAILURE; |
5085 | 0 | } |
5086 | 0 | |
5087 | 0 | nsCOMPtr<nsIFile> appOmni; |
5088 | 0 | if (path) { |
5089 | 0 | rv = XRE_GetFileFromPath(path, getter_AddRefs(appOmni)); |
5090 | 0 | if (NS_FAILED(rv)) { |
5091 | 0 | PR_fprintf(PR_STDERR, "Error: argument --appomni requires a valid path\n"); |
5092 | 0 | return rv; |
5093 | 0 | } |
5094 | 0 | } |
5095 | 0 | |
5096 | 0 | mozilla::Omnijar::Init(greOmni, appOmni); |
5097 | 0 | return rv; |
5098 | 0 | } |
5099 | | |
5100 | | nsresult |
5101 | | XRE_DeinitCommandLine() |
5102 | 0 | { |
5103 | 0 | nsresult rv = NS_OK; |
5104 | 0 |
|
5105 | 0 | CommandLine::Terminate(); |
5106 | 0 |
|
5107 | 0 | return rv; |
5108 | 0 | } |
5109 | | |
5110 | | GeckoProcessType |
5111 | | XRE_GetProcessType() |
5112 | 4.51k | { |
5113 | 4.51k | return mozilla::startup::sChildProcessType; |
5114 | 4.51k | } |
5115 | | |
5116 | | bool |
5117 | | XRE_IsGPUProcess() |
5118 | 0 | { |
5119 | 0 | return XRE_GetProcessType() == GeckoProcessType_GPU; |
5120 | 0 | } |
5121 | | |
5122 | | bool |
5123 | | XRE_IsVRProcess() |
5124 | 0 | { |
5125 | 0 | return XRE_GetProcessType() == GeckoProcessType_VR; |
5126 | 0 | } |
5127 | | |
5128 | | /** |
5129 | | * Returns true in the e10s parent process and in the main process when e10s |
5130 | | * is disabled. |
5131 | | */ |
5132 | | bool |
5133 | | XRE_IsParentProcess() |
5134 | 1.35k | { |
5135 | 1.35k | return XRE_GetProcessType() == GeckoProcessType_Default; |
5136 | 1.35k | } |
5137 | | |
5138 | | bool |
5139 | | XRE_IsE10sParentProcess() |
5140 | 0 | { |
5141 | 0 | return XRE_IsParentProcess() && BrowserTabsRemoteAutostart(); |
5142 | 0 | } |
5143 | | |
5144 | | bool |
5145 | | XRE_IsContentProcess() |
5146 | 156 | { |
5147 | 156 | return XRE_GetProcessType() == GeckoProcessType_Content; |
5148 | 156 | } |
5149 | | |
5150 | | bool |
5151 | | XRE_IsPluginProcess() |
5152 | 0 | { |
5153 | 0 | return XRE_GetProcessType() == GeckoProcessType_Plugin; |
5154 | 0 | } |
5155 | | |
5156 | | bool |
5157 | | XRE_UseNativeEventProcessing() |
5158 | 0 | { |
5159 | 0 | if (XRE_IsContentProcess()) { |
5160 | 0 | static bool sInited = false; |
5161 | 0 | static bool sUseNativeEventProcessing = false; |
5162 | 0 | if (!sInited) { |
5163 | 0 | Preferences::AddBoolVarCache(&sUseNativeEventProcessing, |
5164 | 0 | "dom.ipc.useNativeEventProcessing.content"); |
5165 | 0 | sInited = true; |
5166 | 0 | } |
5167 | 0 |
|
5168 | 0 | return sUseNativeEventProcessing; |
5169 | 0 | } |
5170 | 0 |
|
5171 | 0 | return true; |
5172 | 0 | } |
5173 | | |
5174 | | // If you add anything to this enum, please update about:support to reflect it |
5175 | | enum { |
5176 | | kE10sEnabledByUser = 0, |
5177 | | kE10sEnabledByDefault = 1, |
5178 | | kE10sDisabledByUser = 2, |
5179 | | // kE10sDisabledInSafeMode = 3, was removed in bug 1172491. |
5180 | | // kE10sDisabledForAccessibility = 4, |
5181 | | // kE10sDisabledForMacGfx = 5, was removed in bug 1068674. |
5182 | | // kE10sDisabledForBidi = 6, removed in bug 1309599 |
5183 | | // kE10sDisabledForAddons = 7, removed in bug 1406212 |
5184 | | kE10sForceDisabled = 8, |
5185 | | // kE10sDisabledForXPAcceleration = 9, removed in bug 1296353 |
5186 | | // kE10sDisabledForOperatingSystem = 10, removed due to xp-eol |
5187 | | }; |
5188 | | |
5189 | | const char* kForceEnableE10sPref = "browser.tabs.remote.force-enable"; |
5190 | | const char* kForceDisableE10sPref = "browser.tabs.remote.force-disable"; |
5191 | | |
5192 | | namespace mozilla { |
5193 | | |
5194 | | bool |
5195 | | BrowserTabsRemoteAutostart() |
5196 | 0 | { |
5197 | 0 | if (gBrowserTabsRemoteAutostartInitialized) { |
5198 | 0 | return gBrowserTabsRemoteAutostart; |
5199 | 0 | } |
5200 | 0 | gBrowserTabsRemoteAutostartInitialized = true; |
5201 | 0 |
|
5202 | 0 | // If we're in the content process, we are running E10S. |
5203 | 0 | if (XRE_IsContentProcess()) { |
5204 | 0 | gBrowserTabsRemoteAutostart = true; |
5205 | 0 | return gBrowserTabsRemoteAutostart; |
5206 | 0 | } |
5207 | 0 | |
5208 | 0 | bool optInPref = Preferences::GetBool("browser.tabs.remote.autostart", true); |
5209 | 0 | int status = kE10sEnabledByDefault; |
5210 | 0 |
|
5211 | 0 | if (optInPref) { |
5212 | 0 | gBrowserTabsRemoteAutostart = true; |
5213 | 0 | } else { |
5214 | 0 | status = kE10sDisabledByUser; |
5215 | 0 | } |
5216 | 0 |
|
5217 | 0 | // Uber override pref for manual testing purposes |
5218 | 0 | if (Preferences::GetBool(kForceEnableE10sPref, false)) { |
5219 | 0 | gBrowserTabsRemoteAutostart = true; |
5220 | 0 | status = kE10sEnabledByUser; |
5221 | 0 | } |
5222 | 0 |
|
5223 | 0 | // Uber override pref for emergency blocking |
5224 | 0 | if (gBrowserTabsRemoteAutostart && |
5225 | 0 | (Preferences::GetBool(kForceDisableE10sPref, false) || |
5226 | 0 | EnvHasValue("MOZ_FORCE_DISABLE_E10S"))) { |
5227 | 0 | gBrowserTabsRemoteAutostart = false; |
5228 | 0 | status = kE10sForceDisabled; |
5229 | 0 | } |
5230 | 0 |
|
5231 | 0 | gBrowserTabsRemoteStatus = status; |
5232 | 0 |
|
5233 | 0 | return gBrowserTabsRemoteAutostart; |
5234 | 0 | } |
5235 | | |
5236 | | uint32_t |
5237 | | GetMaxWebProcessCount() |
5238 | 0 | { |
5239 | 0 | // multiOptOut is in int to allow us to run multiple experiments without |
5240 | 0 | // introducing multiple prefs a la the autostart.N prefs. |
5241 | 0 | if (Preferences::GetInt("dom.ipc.multiOptOut", 0) >= |
5242 | 0 | nsIXULRuntime::E10S_MULTI_EXPERIMENT) { |
5243 | 0 | return 1; |
5244 | 0 | } |
5245 | 0 | |
5246 | 0 | const char* optInPref = "dom.ipc.processCount"; |
5247 | 0 | uint32_t optInPrefValue = Preferences::GetInt(optInPref, 1); |
5248 | 0 | return std::max(1u, optInPrefValue); |
5249 | 0 | } |
5250 | | |
5251 | | const char* |
5252 | | PlatformBuildID() |
5253 | 3 | { |
5254 | 3 | return gToolkitBuildID; |
5255 | 3 | } |
5256 | | |
5257 | | } // namespace mozilla |
5258 | | |
5259 | | void |
5260 | | SetupErrorHandling(const char* progname) |
5261 | 3 | { |
5262 | | #ifdef XP_WIN |
5263 | | /* On Windows XPSP3 and Windows Vista if DEP is configured off-by-default |
5264 | | we still want DEP protection: enable it explicitly and programmatically. |
5265 | | |
5266 | | This function is not available on WinXPSP2 so we dynamically load it. |
5267 | | */ |
5268 | | |
5269 | | HMODULE kernel32 = GetModuleHandleW(L"kernel32.dll"); |
5270 | | SetProcessDEPPolicyFunc _SetProcessDEPPolicy = |
5271 | | (SetProcessDEPPolicyFunc) GetProcAddress(kernel32, "SetProcessDEPPolicy"); |
5272 | | if (_SetProcessDEPPolicy) |
5273 | | _SetProcessDEPPolicy(PROCESS_DEP_ENABLE); |
5274 | | #endif |
5275 | | |
5276 | | #ifdef XP_WIN32 |
5277 | | // Suppress the "DLL Foo could not be found" dialog, such that if dependent |
5278 | | // libraries (such as GDI+) are not preset, we gracefully fail to load those |
5279 | | // XPCOM components, instead of being ungraceful. |
5280 | | UINT realMode = SetErrorMode(0); |
5281 | | realMode |= SEM_FAILCRITICALERRORS; |
5282 | | // If XRE_NO_WINDOWS_CRASH_DIALOG is set, suppress displaying the "This |
5283 | | // application has crashed" dialog box. This is mainly useful for |
5284 | | // automated testing environments, e.g. tinderbox, where there's no need |
5285 | | // for a dozen of the dialog boxes to litter the console |
5286 | | if (getenv("XRE_NO_WINDOWS_CRASH_DIALOG")) |
5287 | | realMode |= SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX; |
5288 | | |
5289 | | SetErrorMode(realMode); |
5290 | | |
5291 | | #endif |
5292 | | |
5293 | 3 | InstallSignalHandlers(progname); |
5294 | 3 | |
5295 | 3 | // Unbuffer stdout, needed for tinderbox tests. |
5296 | 3 | setbuf(stdout, 0); |
5297 | 3 | } |
5298 | | |
5299 | | // Note: This function should not be needed anymore. See Bug 818634 for details. |
5300 | | void |
5301 | 0 | OverrideDefaultLocaleIfNeeded() { |
5302 | 0 | // Read pref to decide whether to override default locale with US English. |
5303 | 0 | if (mozilla::Preferences::GetBool("javascript.use_us_english_locale", false)) { |
5304 | 0 | // Set the application-wide C-locale. Needed to resist fingerprinting |
5305 | 0 | // of Date.toLocaleFormat(). We use the locale to "C.UTF-8" if possible, |
5306 | 0 | // to avoid interfering with non-ASCII keyboard input on some Linux desktops. |
5307 | 0 | // Otherwise fall back to the "C" locale, which is available on all platforms. |
5308 | 0 | setlocale(LC_ALL, "C.UTF-8") || setlocale(LC_ALL, "C"); |
5309 | 0 | } |
5310 | 0 | } |
5311 | | |
5312 | | void |
5313 | 3 | XRE_EnableSameExecutableForContentProc() { |
5314 | 3 | if (!PR_GetEnv("MOZ_SEPARATE_CHILD_PROCESS")) { |
5315 | 3 | mozilla::ipc::GeckoChildProcessHost::EnableSameExecutableForContentProc(); |
5316 | 3 | } |
5317 | 3 | } |
5318 | | |
5319 | | // Because rust doesn't handle weak symbols, this function wraps the weak |
5320 | | // malloc_handle_oom for it. |
5321 | | extern "C" void |
5322 | 0 | GeckoHandleOOM(size_t size) { |
5323 | 0 | mozalloc_handle_oom(size); |
5324 | 0 | } |
5325 | | |
5326 | | #ifdef MOZ_ASAN_REPORTER |
5327 | | void setASanReporterPath(nsIFile* aDir) { |
5328 | | nsCOMPtr<nsIFile> dir; |
5329 | | aDir->Clone(getter_AddRefs(dir)); |
5330 | | |
5331 | | dir->Append(NS_LITERAL_STRING("asan")); |
5332 | | nsresult rv = dir->Create(nsIFile::DIRECTORY_TYPE, 0700); |
5333 | | if (NS_WARN_IF(NS_FAILED(rv) && rv != NS_ERROR_FILE_ALREADY_EXISTS)) { |
5334 | | MOZ_CRASH("[ASan Reporter] Unable to create crash directory."); |
5335 | | } |
5336 | | |
5337 | | dir->Append(NS_LITERAL_STRING("ff_asan_log")); |
5338 | | |
5339 | | #ifdef XP_WIN |
5340 | | nsAutoString nspathW; |
5341 | | rv = dir->GetPath(nspathW); |
5342 | | NS_ConvertUTF16toUTF8 nspath(nspathW); |
5343 | | #else |
5344 | | nsAutoCString nspath; |
5345 | | rv = dir->GetNativePath(nspath); |
5346 | | #endif |
5347 | | if (NS_FAILED(rv)) { |
5348 | | MOZ_CRASH("[ASan Reporter] Unable to get native path for crash directory."); |
5349 | | } |
5350 | | |
5351 | | __sanitizer_set_report_path(nspath.get()); |
5352 | | } |
5353 | | #endif |