Backed out changeset 496886cb30a5 (bug 1867152) for bc failures on browser_user_input...
[gecko.git] / browser / app / nsBrowserApp.cpp
blob3145342155865bc283c79b8c026664b4956ac864
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/. */
6 #include "nsXULAppAPI.h"
7 #include "mozilla/XREAppData.h"
8 #include "XREShellData.h"
9 #include "application.ini.h"
10 #include "mozilla/Bootstrap.h"
11 #include "mozilla/ProcessType.h"
12 #include "mozilla/RuntimeExceptionModule.h"
13 #include "mozilla/ScopeExit.h"
14 #include "BrowserDefines.h"
15 #if defined(XP_WIN)
16 # include <windows.h>
17 # include <stdlib.h>
18 #elif defined(XP_UNIX)
19 # include <sys/resource.h>
20 # include <unistd.h>
21 # include <fcntl.h>
22 #endif
24 #include <stdio.h>
25 #include <stdarg.h>
26 #include <time.h>
28 #include "nsCOMPtr.h"
30 #ifdef XP_WIN
31 # include "mozilla/PreXULSkeletonUI.h"
32 # include "freestanding/SharedSection.h"
33 # include "LauncherProcessWin.h"
34 # include "mozilla/GeckoArgs.h"
35 # include "mozilla/mscom/ProcessRuntime.h"
36 # include "mozilla/WindowsDllBlocklist.h"
37 # include "mozilla/WindowsDpiInitialization.h"
38 # include "mozilla/WindowsProcessMitigations.h"
40 # define XRE_WANT_ENVIRON
41 # define strcasecmp _stricmp
42 # ifdef MOZ_SANDBOX
43 # include "mozilla/sandboxing/SandboxInitialization.h"
44 # endif
45 #endif
46 #include "BinaryPath.h"
48 #include "nsXPCOMPrivate.h" // for MAXPATHLEN and XPCOM_DLL
50 #include "mozilla/Sprintf.h"
51 #include "mozilla/StartupTimeline.h"
52 #include "BaseProfiler.h"
54 #ifdef LIBFUZZER
55 # include "FuzzerDefs.h"
56 #endif
58 #ifdef MOZ_LINUX_32_SSE2_STARTUP_ERROR
59 # include <cpuid.h>
60 # include "mozilla/Unused.h"
62 static bool IsSSE2Available() {
63 // The rest of the app has been compiled to assume that SSE2 is present
64 // unconditionally, so we can't use the normal copy of SSE.cpp here.
65 // Since SSE.cpp caches the results and we need them only transiently,
66 // instead of #including SSE.cpp here, let's just inline the specific check
67 // that's needed.
68 unsigned int level = 1u;
69 unsigned int eax, ebx, ecx, edx;
70 unsigned int bits = (1u << 26);
71 unsigned int max = __get_cpuid_max(0, nullptr);
72 if (level > max) {
73 return false;
75 __cpuid_count(level, 0, eax, ebx, ecx, edx);
76 return (edx & bits) == bits;
79 static const char sSSE2Message[] =
80 "This browser version requires a processor with the SSE2 instruction "
81 "set extension.\nYou may be able to obtain a version that does not "
82 "require SSE2 from your Linux distribution.\n";
84 __attribute__((constructor)) static void SSE2Check() {
85 if (IsSSE2Available()) {
86 return;
88 // Using write() in order to avoid jemalloc-based buffering. Ignoring return
89 // values, since there isn't much we could do on failure and there is no
90 // point in trying to recover from errors.
91 MOZ_UNUSED(
92 write(STDERR_FILENO, sSSE2Message, MOZ_ARRAY_LENGTH(sSSE2Message) - 1));
93 // _exit() instead of exit() to avoid running the usual "at exit" code.
94 _exit(255);
96 #endif
98 #if !defined(MOZ_WIDGET_COCOA) && !defined(MOZ_WIDGET_ANDROID)
99 # define MOZ_BROWSER_CAN_BE_CONTENTPROC
100 # include "../../ipc/contentproc/plugin-container.cpp"
101 #endif
103 using namespace mozilla;
105 #ifdef XP_MACOSX
106 # define kOSXResourcesFolder "Resources"
107 #endif
108 #define kDesktopFolder "browser"
110 static MOZ_FORMAT_PRINTF(1, 2) void Output(const char* fmt, ...) {
111 va_list ap;
112 va_start(ap, fmt);
114 #ifndef XP_WIN
115 vfprintf(stderr, fmt, ap);
116 #else
117 char msg[2048];
118 vsnprintf_s(msg, _countof(msg), _TRUNCATE, fmt, ap);
120 wchar_t wide_msg[2048];
121 MultiByteToWideChar(CP_UTF8, 0, msg, -1, wide_msg, _countof(wide_msg));
122 # if MOZ_WINCONSOLE
123 fwprintf_s(stderr, wide_msg);
124 # else
125 // Linking user32 at load-time interferes with the DLL blocklist (bug 932100).
126 // This is a rare codepath, so we can load user32 at run-time instead.
127 HMODULE user32 = LoadLibraryW(L"user32.dll");
128 if (user32) {
129 decltype(MessageBoxW)* messageBoxW =
130 (decltype(MessageBoxW)*)GetProcAddress(user32, "MessageBoxW");
131 if (messageBoxW) {
132 messageBoxW(nullptr, wide_msg, L"Firefox",
133 MB_OK | MB_ICONERROR | MB_SETFOREGROUND);
135 FreeLibrary(user32);
137 # endif
138 #endif
140 va_end(ap);
144 * Return true if |arg| matches the given argument name.
146 static bool IsArg(const char* arg, const char* s) {
147 if (*arg == '-') {
148 if (*++arg == '-') ++arg;
149 return !strcasecmp(arg, s);
152 #if defined(XP_WIN)
153 if (*arg == '/') return !strcasecmp(++arg, s);
154 #endif
156 return false;
159 Bootstrap::UniquePtr gBootstrap;
161 static int do_main(int argc, char* argv[], char* envp[]) {
162 // Allow firefox.exe to launch XULRunner apps via -app <application.ini>
163 // Note that -app must be the *first* argument.
164 const char* appDataFile = getenv("XUL_APP_FILE");
165 if ((!appDataFile || !*appDataFile) && (argc > 1 && IsArg(argv[1], "app"))) {
166 if (argc == 2) {
167 Output("Incorrect number of arguments passed to -app");
168 return 255;
170 appDataFile = argv[2];
172 char appEnv[MAXPATHLEN];
173 SprintfLiteral(appEnv, "XUL_APP_FILE=%s", argv[2]);
174 if (putenv(strdup(appEnv))) {
175 Output("Couldn't set %s.\n", appEnv);
176 return 255;
178 argv[2] = argv[0];
179 argv += 2;
180 argc -= 2;
181 } else if (argc > 1 && IsArg(argv[1], "xpcshell")) {
182 for (int i = 1; i < argc; i++) {
183 argv[i] = argv[i + 1];
186 XREShellData shellData;
187 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
188 shellData.sandboxBrokerServices =
189 sandboxing::GetInitializedBrokerServices();
190 #endif
192 #ifdef LIBFUZZER
193 shellData.fuzzerDriver = fuzzer::FuzzerDriver;
194 #endif
196 return gBootstrap->XRE_XPCShellMain(--argc, argv, envp, &shellData);
199 BootstrapConfig config;
201 if (appDataFile && *appDataFile) {
202 config.appData = nullptr;
203 config.appDataPath = appDataFile;
204 } else {
205 // no -app flag so we use the compiled-in app data
206 config.appData = &sAppData;
207 config.appDataPath = kDesktopFolder;
210 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
211 sandbox::BrokerServices* brokerServices =
212 sandboxing::GetInitializedBrokerServices();
213 if (!brokerServices) {
214 Output("Couldn't initialize the broker services.\n");
215 return 255;
217 config.sandboxBrokerServices = brokerServices;
218 #endif
220 #ifdef LIBFUZZER
221 if (getenv("FUZZER"))
222 gBootstrap->XRE_LibFuzzerSetDriver(fuzzer::FuzzerDriver);
223 #endif
225 EnsureBrowserCommandlineSafe(argc, argv);
227 return gBootstrap->XRE_main(argc, argv, config);
230 static nsresult InitXPCOMGlue(LibLoadingStrategy aLibLoadingStrategy) {
231 if (gBootstrap) {
232 return NS_OK;
235 UniqueFreePtr<char> exePath = BinaryPath::Get();
236 if (!exePath) {
237 Output("Couldn't find the application directory.\n");
238 return NS_ERROR_FAILURE;
241 auto bootstrapResult =
242 mozilla::GetBootstrap(exePath.get(), aLibLoadingStrategy);
243 if (bootstrapResult.isErr()) {
244 Output("Couldn't load XPCOM.\n");
245 return NS_ERROR_FAILURE;
248 gBootstrap = bootstrapResult.unwrap();
250 // This will set this thread as the main thread.
251 gBootstrap->NS_LogInit();
253 return NS_OK;
256 #ifdef HAS_DLL_BLOCKLIST
257 // NB: This must be extern, as this value is checked elsewhere
258 uint32_t gBlocklistInitFlags = eDllBlocklistInitFlagDefault;
259 #endif
261 #if defined(XP_UNIX)
262 static void ReserveDefaultFileDescriptors() {
263 // Reserve the lower positions of the file descriptors to make sure
264 // we don't reuse stdin/stdout/stderr in case they we closed
265 // before launch.
266 // Otherwise code explicitly writing to fd 1 or 2 might accidentally
267 // write to something else, like in bug 1820896 where FD 1 is
268 // reused for the X server display connection.
269 int fd = open("/dev/null", O_RDONLY);
270 for (int i = 0; i < 2; i++) {
271 mozilla::Unused << dup(fd);
274 #endif
276 int main(int argc, char* argv[], char* envp[]) {
277 #if defined(XP_UNIX)
278 ReserveDefaultFileDescriptors();
279 #endif
280 #if defined(MOZ_ENABLE_FORKSERVER)
281 if (strcmp(argv[argc - 1], "forkserver") == 0) {
282 nsresult rv = InitXPCOMGlue(LibLoadingStrategy::NoReadAhead);
283 if (NS_FAILED(rv)) {
284 return 255;
287 // Run a fork server in this process, single thread. When it
288 // returns, it means the fork server have been stopped or a new
289 // content process is created.
291 // For the later case, XRE_ForkServer() will return false, running
292 // in a content process just forked from the fork server process.
293 // argc & argv will be updated with the values passing from the
294 // chrome process. With the new values, this function
295 // continues the reset of the code acting as a content process.
296 if (gBootstrap->XRE_ForkServer(&argc, &argv)) {
297 // Return from the fork server in the fork server process.
298 // Stop the fork server.
299 gBootstrap->NS_LogTerm();
300 return 0;
302 // In a content process forked from the fork server.
303 // Start acting as a content process.
305 #endif
307 mozilla::TimeStamp start = mozilla::TimeStamp::Now();
309 AUTO_BASE_PROFILER_INIT;
310 AUTO_BASE_PROFILER_LABEL("nsBrowserApp main", OTHER);
312 // Make sure we unregister the runtime exception module before returning.
313 // We do this here to cover both registers for child and main processes.
314 auto unregisterRuntimeExceptionModule =
315 MakeScopeExit([] { CrashReporter::UnregisterRuntimeExceptionModule(); });
317 #ifdef MOZ_BROWSER_CAN_BE_CONTENTPROC
318 // We are launching as a content process, delegate to the appropriate
319 // main
320 if (argc > 1 && IsArg(argv[1], "contentproc")) {
321 // Set the process type. We don't remove the arg here as that will be done
322 // later in common code.
323 SetGeckoProcessType(argv[argc - 1]);
325 // Register an external module to report on otherwise uncatchable
326 // exceptions. Note that in child processes this must be called after Gecko
327 // process type has been set.
328 CrashReporter::RegisterRuntimeExceptionModule();
330 # if defined(XP_WIN) && defined(MOZ_SANDBOX)
331 // We need to set whether our process is supposed to have win32k locked down
332 // from the command line setting before DllBlocklist_Initialize,
333 // GetInitializedTargetServices and WindowsDpiInitialization.
334 Maybe<bool> win32kLockedDown =
335 mozilla::geckoargs::sWin32kLockedDown.Get(argc, argv);
336 if (win32kLockedDown.isSome() && *win32kLockedDown) {
337 mozilla::SetWin32kLockedDownInPolicy();
339 # endif
341 # ifdef HAS_DLL_BLOCKLIST
342 uint32_t initFlags =
343 gBlocklistInitFlags | eDllBlocklistInitFlagIsChildProcess;
344 SetDllBlocklistProcessTypeFlags(initFlags, GetGeckoProcessType());
345 DllBlocklist_Initialize(initFlags);
346 # endif // HAS_DLL_BLOCKLIST
348 # if defined(XP_WIN) && defined(MOZ_SANDBOX)
349 // We need to initialize the sandbox TargetServices before InitXPCOMGlue
350 // because we might need the sandbox broker to give access to some files.
351 if (IsSandboxedProcess() && !sandboxing::GetInitializedTargetServices()) {
352 Output("Failed to initialize the sandbox target services.");
353 return 255;
355 # endif
356 # if defined(XP_WIN)
357 // Ideally, we would be able to set our DPI awareness in
358 // firefox.exe.manifest Unfortunately, that would cause Win32k calls when
359 // user32.dll gets loaded, which would be incompatible with Win32k Lockdown
361 // MSDN says that it's allowed-but-not-recommended to initialize DPI
362 // programatically, as long as it's done before any HWNDs are created.
363 // Thus, we do it almost as soon as we possibly can
365 auto result = mozilla::WindowsDpiInitialization();
366 (void)result; // Ignore errors since some tools block DPI calls
368 # endif
370 nsresult rv = InitXPCOMGlue(LibLoadingStrategy::NoReadAhead);
371 if (NS_FAILED(rv)) {
372 return 255;
375 int result = content_process_main(gBootstrap.get(), argc, argv);
377 # if defined(DEBUG) && defined(HAS_DLL_BLOCKLIST)
378 DllBlocklist_Shutdown();
379 # endif
381 // InitXPCOMGlue calls NS_LogInit, so we need to balance it here.
382 gBootstrap->NS_LogTerm();
384 return result;
386 #endif
388 // Register an external module to report on otherwise uncatchable exceptions.
389 CrashReporter::RegisterRuntimeExceptionModule();
391 #ifdef HAS_DLL_BLOCKLIST
392 DllBlocklist_Initialize(gBlocklistInitFlags);
393 #endif
395 // We will likely only ever support this as a command line argument on Windows
396 // and OSX, so we're ifdefing here just to not create any expectations.
397 #if defined(XP_WIN) || defined(XP_MACOSX)
398 if (argc > 1 && IsArg(argv[1], "silentmode")) {
399 ::putenv(const_cast<char*>("MOZ_APP_SILENT_START=1"));
400 # if defined(XP_WIN)
401 // On windows We also want to set a separate variable, which we want to
402 // persist across restarts, which will let us keep the process alive
403 // even if the last window is closed.
404 ::putenv(const_cast<char*>("MOZ_APP_ALLOW_WINDOWLESS=1"));
405 # endif
406 # if defined(XP_MACOSX)
407 ::putenv(const_cast<char*>("MOZ_APP_NO_DOCK=1"));
408 # endif
410 #endif
412 #if defined(XP_WIN)
414 // Ideally, we would be able to set our DPI awareness in firefox.exe.manifest
415 // Unfortunately, that would cause Win32k calls when user32.dll gets loaded,
416 // which would be incompatible with Win32k Lockdown
418 // MSDN says that it's allowed-but-not-recommended to initialize DPI
419 // programatically, as long as it's done before any HWNDs are created.
420 // Thus, we do it almost as soon as we possibly can
422 auto result = mozilla::WindowsDpiInitialization();
423 (void)result; // Ignore errors since some tools block DPI calls
426 // Once the browser process hits the main function, we no longer need
427 // a writable section handle because all dependent modules have been
428 // loaded.
429 mozilla::freestanding::gSharedSection.ConvertToReadOnly();
431 mozilla::CreateAndStorePreXULSkeletonUI(GetModuleHandle(nullptr), argc, argv);
432 #endif
434 nsresult rv = InitXPCOMGlue(LibLoadingStrategy::ReadAhead);
435 if (NS_FAILED(rv)) {
436 return 255;
439 gBootstrap->XRE_StartupTimelineRecord(mozilla::StartupTimeline::START, start);
441 #ifdef MOZ_BROWSER_CAN_BE_CONTENTPROC
442 gBootstrap->XRE_EnableSameExecutableForContentProc();
443 #endif
445 int result = do_main(argc, argv, envp);
447 #if defined(XP_WIN)
448 CleanupProcessRuntime();
449 #endif
451 gBootstrap->NS_LogTerm();
453 #if defined(DEBUG) && defined(HAS_DLL_BLOCKLIST)
454 DllBlocklist_Shutdown();
455 #endif
457 #ifdef XP_MACOSX
458 // Allow writes again. While we would like to catch writes from static
459 // destructors to allow early exits to use _exit, we know that there is
460 // at least one such write that we don't control (see bug 826029). For
461 // now we enable writes again and early exits will have to use exit instead
462 // of _exit.
463 gBootstrap->XRE_StopLateWriteChecks();
464 #endif
466 gBootstrap.reset();
468 return result;